Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/BoundsCalculators/GilmoreLawlerBoundCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/BoundsCalculators/GilmoreLawlerBoundCalculator.cs	(revision 7877)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/BoundsCalculators/GilmoreLawlerBoundCalculator.cs	(revision 7877)
@@ -0,0 +1,62 @@
+﻿#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;
+using HeuristicLab.Data;
+using HeuristicLab.Problems.LinearAssignment;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  public static class GilmoreLawlerBoundCalculator {
+    public static double CalculateLowerBound(DoubleMatrix weights, DoubleMatrix distances) {
+      int N = weights.Rows;
+      DoubleMatrix sortedWeights = SortEachRowExceptDiagonal(weights), sortedDistances = SortEachRowExceptDiagonal(distances);
+
+      DoubleMatrix costs = new DoubleMatrix(N, N);
+      for (int i = 0; i < N; i++) {
+        for (int j = 0; j < N; j++) {
+          for (int k = 0; k < N - 1; k++)
+            costs[i, j] += sortedWeights[i, k] * sortedDistances[j, N - 2 - k];
+          costs[i, j] += weights[i, i] * distances[j, j];
+        }
+      }
+
+      double result;
+      LinearAssignmentProblemSolver.Solve(costs, out result);
+      return result;
+    }
+
+    private static DoubleMatrix SortEachRowExceptDiagonal(DoubleMatrix matrix) {
+      var result = new DoubleMatrix(matrix.Rows, matrix.Columns);
+
+      double[] row = new double[matrix.Rows - 1];
+      for (int i = 0; i < matrix.Rows; i++) {
+        int counter = 0;
+        for (int j = 0; j < matrix.Columns; j++)
+          if (i != j) row[counter++] = matrix[i, j];
+        Array.Sort(row);
+        for (int k = 0; k < matrix.Columns - 1; k++)
+          result[i, k] = row[k];
+        result[i, matrix.Columns - 1] = matrix[i, i];
+      }
+      return result;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 7875)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 7877)
@@ -114,4 +114,5 @@
     <Compile Include="Analyzers\QAPAlleleFrequencyAnalyzer.cs" />
     <Compile Include="Analyzers\QAPPopulationDiversityAnalyzer.cs" />
+    <Compile Include="BoundsCalculators\GilmoreLawlerBoundCalculator.cs" />
     <Compile Include="Evaluators\QAPScrambleMoveEvaluator.cs" />
     <Compile Include="Evaluators\QAPSwap2MoveEvaluator.cs" />
@@ -202,4 +203,8 @@
       <Private>False</Private>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Problems.LinearAssignment\3.3\HeuristicLab.Problems.LinearAssignment-3.3.csproj">
+      <Project>{7250653F-DE83-4069-8D34-8050E8E45EA1}</Project>
+      <Name>HeuristicLab.Problems.LinearAssignment-3.3</Name>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/Plugin.cs.frame
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/Plugin.cs.frame	(revision 7875)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/Plugin.cs.frame	(revision 7877)
@@ -37,4 +37,5 @@
   [PluginDependency("HeuristicLab.Persistence", "3.3")]
   [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]
+  [PluginDependency("HeuristicLab.Problems.LinearAssignment", "3.3")]
   public class HeuristicLabProblemsQuadraticAssignmentPlugin : PluginBase { }
 }
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs	(revision 7875)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs	(revision 7877)
@@ -60,4 +60,10 @@
       get { return (IValueParameter<DoubleMatrix>)Parameters["Distances"]; }
     }
+    public IValueParameter<DoubleValue> LowerBoundParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["LowerBound"]; }
+    }
+    public IValueParameter<DoubleValue> AverageQualityParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["AverageQuality"]; }
+    }
     #endregion
 
@@ -78,4 +84,12 @@
       get { return DistancesParameter.Value; }
       set { DistancesParameter.Value = value; }
+    }
+    public DoubleValue LowerBound {
+      get { return LowerBoundParameter.Value; }
+      set { LowerBoundParameter.Value = value; }
+    }
+    public DoubleValue AverageQuality {
+      get { return AverageQualityParameter.Value; }
+      set { AverageQualityParameter.Value = value; }
     }
 
@@ -105,8 +119,11 @@
       Parameters.Add(new ValueParameter<DoubleMatrix>("Weights", "The strength of the connection between the facilities.", new DoubleMatrix(5, 5)));
       Parameters.Add(new ValueParameter<DoubleMatrix>("Distances", "The distance matrix which can either be specified directly without the coordinates, or can be calculated automatically from the coordinates.", new DoubleMatrix(5, 5)));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("LowerBound", "The Gilmore-Lawler lower bound to the solution quality."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("AverageQuality", "The expected quality of a random solution."));
 
       Maximization.Value = false;
       MaximizationParameter.Hidden = true;
 
+      WeightsParameter.GetsCollected = false;
       Weights = new DoubleMatrix(new double[,] {
         { 0, 1, 0, 0, 1 },
@@ -117,4 +134,5 @@
       });
 
+      DistancesParameter.GetsCollected = false;
       Distances = new DoubleMatrix(new double[,] {
         {   0, 360, 582, 582, 360 },
@@ -153,6 +171,14 @@
         Parameters.Add(new ValueParameter<DoubleMatrix>("Distances", "The distance matrix which can either be specified directly without the coordinates, or can be calculated automatically from the coordinates.", d));
       }
+      if (!Parameters.ContainsKey("LowerBound")) {
+        Parameters.Add(new OptionalValueParameter<DoubleValue>("LowerBound", "The Gilmore-Lawler lower bound to the solution quality."));
+        LowerBound = new DoubleValue(GilmoreLawlerBoundCalculator.CalculateLowerBound(Weights, Distances));
+      }
+      if (!Parameters.ContainsKey("AverageQuality")) {
+        Parameters.Add(new OptionalValueParameter<DoubleValue>("AverageQuality", "The expected quality of a random solution."));
+        AverageQuality = new DoubleValue(Weights.Average() * Distances.Average() * Weights.Rows * Weights.Rows);
+      }
+      #endregion
       RegisterEventHandlers();
-      #endregion
     }
 
@@ -186,4 +212,5 @@
       Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
       Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
+      Weights.ToStringChanged += new EventHandler(Weights_ToStringChanged);
       ParameterizeSolutionCreator();
       ParameterizeEvaluator();
@@ -211,7 +238,11 @@
       }
     }
+    private void Weights_ToStringChanged(object sender, EventArgs e) {
+      UpdateParameterValues();
+    }
     private void DistancesParameter_ValueChanged(object sender, EventArgs e) {
       Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
       Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
+      Distances.ToStringChanged += new EventHandler(Distances_ToStringChanged);
       ParameterizeSolutionCreator();
       ParameterizeEvaluator();
@@ -239,7 +270,9 @@
       }
     }
+    private void Distances_ToStringChanged(object sender, EventArgs e) {
+      UpdateParameterValues();
+    }
     #endregion
 
-    #region Helpers
     private void RegisterEventHandlers() {
       SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
@@ -248,9 +281,12 @@
       Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
       Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
+      Weights.ToStringChanged += new EventHandler(Weights_ToStringChanged);
       DistancesParameter.ValueChanged += new EventHandler(DistancesParameter_ValueChanged);
       Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
       Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
-    }
-
+      Distances.ToStringChanged += new EventHandler(Distances_ToStringChanged);
+    }
+
+    #region Helpers
     private void InitializeOperators() {
       var defaultOperators = new HashSet<IPermutationOperator>(new IPermutationOperator[] {
@@ -363,4 +399,9 @@
       }
     }
+
+    private void UpdateParameterValues() {
+      LowerBound = new DoubleValue(GilmoreLawlerBoundCalculator.CalculateLowerBound(Weights, Distances));
+      AverageQuality = new DoubleValue(Weights.Average() * Distances.Average() * Weights.Rows * Weights.Rows);
+    }
     #endregion
 
@@ -407,4 +448,5 @@
       BestKnownSolution = null;
       BestKnownSolutions = null;
+      UpdateParameterValues();
     }
 
