Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs	(revision 7415)
@@ -27,14 +27,4 @@
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common {
   public static class ExtensionMethods {
-
-    /// <summary>
-    /// Simply enumerates the sequence by moving over all elements.
-    /// </summary>
-    /// <typeparam name="T">The type of the items that are to be enumerated.</typeparam>
-    /// <param name="source">The enumerable that contains the items.</param>
-    public static void Enumerate<T>(this IEnumerable<T> source) {
-      var enumerator = source.GetEnumerator();
-      while (enumerator.MoveNext()) ;
-    }
 
     /// <summary>
@@ -109,4 +99,58 @@
 
     /// <summary>
+    /// Selects the first element in the sequence where the selected key is the maximum.
+    /// </summary>
+    /// <remarks>
+    /// Runtime complexity of the operation is O(N).
+    /// </remarks>
+    /// <typeparam name="T">The type of the elements.</typeparam>
+    /// <typeparam name="TComparable">The selected key (needs to be an IComparable).</typeparam>
+    /// <param name="source">The enumeration in which the maximum item should be found.</param>
+    /// <param name="keySelector">The function that selects the key.</param>
+    /// <returns>The element in the enumeration where the selected key is the maximum.</returns>
+    public static T SelectMax<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+      IEnumerator<T> enumerator = source.GetEnumerator();
+      if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence is empty!");
+      T result = enumerator.Current;
+      TComparable max = keySelector(result);
+      while (enumerator.MoveNext()) {
+        T item = enumerator.Current;
+        TComparable comparison = keySelector(item);
+        if (comparison.CompareTo(max) > 0) {
+          result = item;
+          max = comparison;
+        }
+      }
+      return result;
+    }
+
+    /// <summary>
+    /// Selects the first element in the sequence where the selected key is the minimum.
+    /// </summary>
+    /// <remarks>
+    /// Runtime complexity of the operation is O(N).
+    /// </remarks>
+    /// <typeparam name="T">The type of the elements.</typeparam>
+    /// <typeparam name="TComparable">The selected key (needs to be an IComparable).</typeparam>
+    /// <param name="source">The enumeration in which the minimum item should be found.</param>
+    /// <param name="keySelector">The function that selects the key.</param>
+    /// <returns>The element in the enumeration where the selected key is the minimum.</returns>
+    public static T SelectMin<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+      IEnumerator<T> enumerator = source.GetEnumerator();
+      if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence is empty!");
+      T result = enumerator.Current;
+      TComparable min = keySelector(result);
+      while (enumerator.MoveNext()) {
+        T item = enumerator.Current;
+        TComparable comparison = keySelector(item);
+        if (comparison.CompareTo(min) < 0) {
+          result = item;
+          min = comparison;
+        }
+      }
+      return result;
+    }
+
+    /// <summary>
     /// Walks an operator graph in that it jumps from one operator to all its operator parameters and yields each operator it touches.
     /// Cycles are detected and not walked twice.
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.Designer.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.Designer.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.Designer.cs	(revision 7415)
@@ -47,6 +47,15 @@
       this.assignmentTreeView = new System.Windows.Forms.TreeView();
       this.label1 = new System.Windows.Forms.Label();
-      this.qualityTextBox = new System.Windows.Forms.TextBox();
-      this.label2 = new System.Windows.Forms.Label();
+      this.qualityLabel = new System.Windows.Forms.Label();
+      this.assignmentGroupBox = new System.Windows.Forms.GroupBox();
+      this.characteristicsGroupBox = new System.Windows.Forms.GroupBox();
+      this.flowDistanceQualityLabel = new System.Windows.Forms.Label();
+      this.label3 = new System.Windows.Forms.Label();
+      this.installationQualityLabel = new System.Windows.Forms.Label();
+      this.label5 = new System.Windows.Forms.Label();
+      this.overbookedCapacityLabel = new System.Windows.Forms.Label();
+      this.label7 = new System.Windows.Forms.Label();
+      this.assignmentGroupBox.SuspendLayout();
+      this.characteristicsGroupBox.SuspendLayout();
       this.SuspendLayout();
       // 
@@ -56,8 +65,8 @@
                   | System.Windows.Forms.AnchorStyles.Left)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.assignmentTreeView.Location = new System.Drawing.Point(3, 50);
+      this.assignmentTreeView.Location = new System.Drawing.Point(6, 19);
       this.assignmentTreeView.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
       this.assignmentTreeView.Name = "assignmentTreeView";
-      this.assignmentTreeView.Size = new System.Drawing.Size(349, 331);
+      this.assignmentTreeView.Size = new System.Drawing.Size(228, 331);
       this.assignmentTreeView.TabIndex = 3;
       // 
@@ -65,5 +74,6 @@
       // 
       this.label1.AutoSize = true;
-      this.label1.Location = new System.Drawing.Point(3, 7);
+      this.label1.Location = new System.Drawing.Point(6, 19);
+      this.label1.Margin = new System.Windows.Forms.Padding(3);
       this.label1.Name = "label1";
       this.label1.Size = new System.Drawing.Size(42, 13);
@@ -71,21 +81,105 @@
       this.label1.Text = "Quality:";
       // 
-      // qualityTextBox
-      // 
-      this.qualityTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+      // qualityLabel
+      // 
+      this.qualityLabel.AutoSize = true;
+      this.qualityLabel.Location = new System.Drawing.Point(91, 19);
+      this.qualityLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.qualityLabel.Name = "qualityLabel";
+      this.qualityLabel.Size = new System.Drawing.Size(10, 13);
+      this.qualityLabel.TabIndex = 4;
+      this.qualityLabel.Text = "-";
+      // 
+      // assignmentGroupBox
+      // 
+      this.assignmentGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                  | System.Windows.Forms.AnchorStyles.Left)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.qualityTextBox.Location = new System.Drawing.Point(51, 4);
-      this.qualityTextBox.Name = "qualityTextBox";
-      this.qualityTextBox.Size = new System.Drawing.Size(301, 20);
-      this.qualityTextBox.TabIndex = 1;
-      // 
-      // label2
-      // 
-      this.label2.AutoSize = true;
-      this.label2.Location = new System.Drawing.Point(3, 31);
-      this.label2.Name = "label2";
-      this.label2.Size = new System.Drawing.Size(64, 13);
-      this.label2.TabIndex = 2;
-      this.label2.Text = "Assignment:";
+      this.assignmentGroupBox.Controls.Add(this.assignmentTreeView);
+      this.assignmentGroupBox.Location = new System.Drawing.Point(217, 3);
+      this.assignmentGroupBox.Name = "assignmentGroupBox";
+      this.assignmentGroupBox.Size = new System.Drawing.Size(240, 356);
+      this.assignmentGroupBox.TabIndex = 5;
+      this.assignmentGroupBox.TabStop = false;
+      this.assignmentGroupBox.Text = "Assignment";
+      // 
+      // characteristicsGroupBox
+      // 
+      this.characteristicsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                  | System.Windows.Forms.AnchorStyles.Left)));
+      this.characteristicsGroupBox.Controls.Add(this.label7);
+      this.characteristicsGroupBox.Controls.Add(this.overbookedCapacityLabel);
+      this.characteristicsGroupBox.Controls.Add(this.label5);
+      this.characteristicsGroupBox.Controls.Add(this.installationQualityLabel);
+      this.characteristicsGroupBox.Controls.Add(this.label3);
+      this.characteristicsGroupBox.Controls.Add(this.flowDistanceQualityLabel);
+      this.characteristicsGroupBox.Controls.Add(this.label1);
+      this.characteristicsGroupBox.Controls.Add(this.qualityLabel);
+      this.characteristicsGroupBox.Location = new System.Drawing.Point(3, 3);
+      this.characteristicsGroupBox.Name = "characteristicsGroupBox";
+      this.characteristicsGroupBox.Size = new System.Drawing.Size(208, 356);
+      this.characteristicsGroupBox.TabIndex = 6;
+      this.characteristicsGroupBox.TabStop = false;
+      this.characteristicsGroupBox.Text = "Characteristics";
+      // 
+      // flowDistanceQualityLabel
+      // 
+      this.flowDistanceQualityLabel.AutoSize = true;
+      this.flowDistanceQualityLabel.Location = new System.Drawing.Point(91, 38);
+      this.flowDistanceQualityLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.flowDistanceQualityLabel.Name = "flowDistanceQualityLabel";
+      this.flowDistanceQualityLabel.Size = new System.Drawing.Size(10, 13);
+      this.flowDistanceQualityLabel.TabIndex = 4;
+      this.flowDistanceQualityLabel.Text = "-";
+      // 
+      // label3
+      // 
+      this.label3.AutoSize = true;
+      this.label3.Location = new System.Drawing.Point(6, 38);
+      this.label3.Margin = new System.Windows.Forms.Padding(3);
+      this.label3.Name = "label3";
+      this.label3.Size = new System.Drawing.Size(79, 13);
+      this.label3.TabIndex = 0;
+      this.label3.Text = "Flow/Distance:";
+      // 
+      // installationQualityLabel
+      // 
+      this.installationQualityLabel.AutoSize = true;
+      this.installationQualityLabel.Location = new System.Drawing.Point(91, 57);
+      this.installationQualityLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.installationQualityLabel.Name = "installationQualityLabel";
+      this.installationQualityLabel.Size = new System.Drawing.Size(10, 13);
+      this.installationQualityLabel.TabIndex = 4;
+      this.installationQualityLabel.Text = "-";
+      // 
+      // label5
+      // 
+      this.label5.AutoSize = true;
+      this.label5.Location = new System.Drawing.Point(6, 57);
+      this.label5.Margin = new System.Windows.Forms.Padding(3);
+      this.label5.Name = "label5";
+      this.label5.Size = new System.Drawing.Size(60, 13);
+      this.label5.TabIndex = 0;
+      this.label5.Text = "Installation:";
+      // 
+      // overbookedCapacityLabel
+      // 
+      this.overbookedCapacityLabel.AutoSize = true;
+      this.overbookedCapacityLabel.Location = new System.Drawing.Point(91, 76);
+      this.overbookedCapacityLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.overbookedCapacityLabel.Name = "overbookedCapacityLabel";
+      this.overbookedCapacityLabel.Size = new System.Drawing.Size(10, 13);
+      this.overbookedCapacityLabel.TabIndex = 4;
+      this.overbookedCapacityLabel.Text = "-";
+      // 
+      // label7
+      // 
+      this.label7.AutoSize = true;
+      this.label7.Location = new System.Drawing.Point(6, 76);
+      this.label7.Margin = new System.Windows.Forms.Padding(3);
+      this.label7.Name = "label7";
+      this.label7.Size = new System.Drawing.Size(71, 13);
+      this.label7.TabIndex = 0;
+      this.label7.Text = "Overbooking:";
       // 
       // GQAPAssignmentView
@@ -93,12 +187,12 @@
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.qualityTextBox);
-      this.Controls.Add(this.label2);
-      this.Controls.Add(this.label1);
-      this.Controls.Add(this.assignmentTreeView);
+      this.Controls.Add(this.characteristicsGroupBox);
+      this.Controls.Add(this.assignmentGroupBox);
       this.Name = "GQAPAssignmentView";
-      this.Size = new System.Drawing.Size(355, 384);
+      this.Size = new System.Drawing.Size(460, 362);
+      this.assignmentGroupBox.ResumeLayout(false);
+      this.characteristicsGroupBox.ResumeLayout(false);
+      this.characteristicsGroupBox.PerformLayout();
       this.ResumeLayout(false);
-      this.PerformLayout();
 
     }
@@ -108,6 +202,13 @@
     private System.Windows.Forms.TreeView assignmentTreeView;
     private System.Windows.Forms.Label label1;
-    private System.Windows.Forms.TextBox qualityTextBox;
-    private System.Windows.Forms.Label label2;
+    private System.Windows.Forms.Label qualityLabel;
+    private System.Windows.Forms.GroupBox assignmentGroupBox;
+    private System.Windows.Forms.GroupBox characteristicsGroupBox;
+    private System.Windows.Forms.Label label3;
+    private System.Windows.Forms.Label flowDistanceQualityLabel;
+    private System.Windows.Forms.Label label7;
+    private System.Windows.Forms.Label overbookedCapacityLabel;
+    private System.Windows.Forms.Label label5;
+    private System.Windows.Forms.Label installationQualityLabel;
   }
 }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.cs	(revision 7415)
@@ -22,4 +22,5 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Windows.Forms;
@@ -44,10 +45,10 @@
     #region Register Content Events
     protected override void DeregisterContentEvents() {
-      // TODO: Deregister your event handlers on the Content here
+      Content.PropertyChanged -= new PropertyChangedEventHandler(Content_PropertyChanged);
       base.DeregisterContentEvents();
     }
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
-      // TODO: Register your event handlers on the Content here
+      Content.PropertyChanged += new PropertyChangedEventHandler(Content_PropertyChanged);
     }
     #endregion
@@ -55,46 +56,100 @@
     protected override void OnContentChanged() {
       base.OnContentChanged();
-      assignmentTreeView.Nodes.Clear();
-      if (Content == null) {
-        qualityTextBox.Text = String.Empty;
-      } else {
-        qualityTextBox.Text = Content.Quality.Value.ToString();
-        BuildAssignmentTree();
-      }
+      UpdateQuality();
+      UpdateAssignment();
     }
 
     protected override void SetEnabledStateOfControls() {
       base.SetEnabledStateOfControls();
-      qualityTextBox.Enabled = false;
-      assignmentTreeView.Enabled = true;
     }
 
     #region Event Handlers
-    // TODO: Put event handlers here
+    private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      switch (e.PropertyName) {
+        case "Quality": UpdateQuality(); break;
+        case "FlowDistanceQuality": UpdateFlowDistanceQuality(); break;
+        case "InstallationQuality": UpdateInstallationQuality(); break;
+        case "OverbookedCapacity": UpdateOverbookedCapacity(); break;
+        case "Assignment": UpdateAssignment(); break;
+        case "EquipmentNames": UpdateAssignment(); break;
+        case "LocationNames": UpdateAssignment(); break;
+        default: break;
+      }
+    }
     #endregion
 
-    private void BuildAssignmentTree() {
-      IntegerVector assignment = Content.Assignment;
-      Dictionary<int, TreeNode> locationNodes = new Dictionary<int, TreeNode>();
-      for (int i = 0; i < assignment.Length; i++) {
-        if (!locationNodes.ContainsKey(assignment[i])) {
-          string locationName = assignment[i].ToString();
-          if (Content.LocationNames != null && Content.LocationNames.Length > 0)
-            locationName = Content.LocationNames[assignment[i] % Content.LocationNames.Length];
-          locationNodes.Add(assignment[i], new TreeNode(locationName));
+    private void UpdateQuality() {
+      if (InvokeRequired) Invoke((Action)UpdateQuality);
+      else {
+        if (Content == null) {
+          qualityLabel.Text = "-";
+        } else {
+          qualityLabel.Text = Content.Quality.ToString();
         }
-        string equipmentName = i.ToString();
-        if (Content.EquipmentNames != null && Content.EquipmentNames.Length > 0)
-          equipmentName = Content.EquipmentNames[i % Content.EquipmentNames.Length];
-        locationNodes[assignment[i]].Nodes.Add(equipmentName);
       }
+    }
 
-      assignmentTreeView.BeginUpdate();
-      try {
-        foreach (var node in locationNodes.OrderBy(x => x.Key).Select(x => x.Value)) {
-          assignmentTreeView.Nodes.Add(node);
-          node.Expand();
+    private void UpdateFlowDistanceQuality() {
+      if (InvokeRequired) Invoke((Action)UpdateFlowDistanceQuality);
+      else {
+        if (Content == null || Content.FlowDistanceQuality == null) {
+          flowDistanceQualityLabel.Text = "-";
+        } else {
+          flowDistanceQualityLabel.Text = Content.FlowDistanceQuality.ToString();
         }
-      } finally { assignmentTreeView.EndUpdate(); }
+      }
+    }
+
+    private void UpdateInstallationQuality() {
+      if (InvokeRequired) Invoke((Action)UpdateInstallationQuality);
+      else {
+        if (Content == null || Content.InstallationQuality == null) {
+          installationQualityLabel.Text = "-";
+        } else {
+          installationQualityLabel.Text = Content.InstallationQuality.ToString();
+        }
+      }
+    }
+
+    private void UpdateOverbookedCapacity() {
+      if (InvokeRequired) Invoke((Action)UpdateOverbookedCapacity);
+      else {
+        if (Content == null || Content.OverbookedCapacity == null) {
+          overbookedCapacityLabel.Text = "-";
+        } else {
+          overbookedCapacityLabel.Text = Content.OverbookedCapacity.ToString();
+        }
+      }
+    }
+
+    private void UpdateAssignment() {
+      if (InvokeRequired) Invoke((Action)UpdateAssignment);
+      else {
+        assignmentTreeView.Nodes.Clear();
+        if (Content != null) {
+          IntegerVector assignment = Content.Assignment;
+          Dictionary<int, TreeNode> locationNodes = new Dictionary<int, TreeNode>();
+          for (int i = 0; i < assignment.Length; i++) {
+            if (!locationNodes.ContainsKey(assignment[i])) {
+              string locationName = assignment[i].ToString();
+              if (Content.LocationNames != null && Content.LocationNames.Length > assignment[i])
+                locationName = Content.LocationNames[assignment[i]];
+              locationNodes.Add(assignment[i], new TreeNode(locationName));
+            }
+            string equipmentName = i.ToString();
+            if (Content.EquipmentNames != null && Content.EquipmentNames.Length > i)
+              equipmentName = Content.EquipmentNames[i];
+            locationNodes[assignment[i]].Nodes.Add(equipmentName);
+          }
+
+          assignmentTreeView.BeginUpdate();
+          try {
+            foreach (var node in locationNodes.OrderBy(x => x.Key).Select(x => x.Value)) {
+              assignmentTreeView.Nodes.Add(node);
+              node.Expand();
+            }
+          } finally { assignmentTreeView.EndUpdate(); }
+        }
+      }
     }
   }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs	(revision 7415)
@@ -29,4 +29,5 @@
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common;
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
@@ -51,4 +52,19 @@
       get { return (LookupParameter<DoubleMatrix>)Parameters["Weights"]; }
     }
+    public LookupParameter<DoubleMatrix> InstallationCostsParameter {
+      get { return (LookupParameter<DoubleMatrix>)Parameters["InstallationCosts"]; }
+    }
+    public LookupParameter<DoubleArray> DemandsParameter {
+      get { return (LookupParameter<DoubleArray>)Parameters["Demands"]; }
+    }
+    public LookupParameter<DoubleArray> CapacitiesParameter {
+      get { return (LookupParameter<DoubleArray>)Parameters["Capacities"]; }
+    }
+    public LookupParameter<DoubleValue> TransportationCostsParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["TransportationCosts"]; }
+    }
+    public LookupParameter<DoubleValue> OverbookedCapacityPenaltyParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["OverbookedCapacityPenalty"]; }
+    }
     public ScopeTreeLookupParameter<IntegerVector> AssignmentParameter {
       get { return (ScopeTreeLookupParameter<IntegerVector>)Parameters["Assignment"]; }
@@ -56,4 +72,13 @@
     public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
       get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> FlowDistanceQualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["FlowDistanceQuality"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> InstallationQualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["InstallationQuality"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> OverbookedCapacityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["OverbookedCapacity"]; }
     }
     public LookupParameter<GQAPAssignment> BestSolutionParameter {
@@ -86,7 +111,15 @@
       Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
       Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances between the locations."));
-      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights between the facilities."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights between the equipments."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("InstallationCosts", "The cost of installing equipment x at location y."));
+      Parameters.Add(new LookupParameter<DoubleArray>("Demands", "The demands of the equipments."));
+      Parameters.Add(new LookupParameter<DoubleArray>("Capacities", "The capacities at the locations."));
+      Parameters.Add(new LookupParameter<DoubleValue>("TransportationCosts", "The transportation cost represents the flow-unit per distance-unit cost factor. This value can also be set to 1 if these costs are factored into the weights matrix already."));
+      Parameters.Add(new LookupParameter<DoubleValue>("OverbookedCapacityPenalty", "The multiplier for the constraint violation when added to the quality."));
       Parameters.Add(new ScopeTreeLookupParameter<IntegerVector>("Assignment", "The GQAP solutions from which the best solution should be analyzed."));
       Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the GQAP solutions which should be analyzed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("FlowDistanceQuality", "The flow-distance qualities of the GQAP solutions which should be analyzed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("InstallationQuality", "The installation qualities of the GQAP solutions which should be analyzed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("OverbookedCapacity", "The overbooked capacities of the GQAP solutions which should be analyzed."));
       Parameters.Add(new LookupParameter<GQAPAssignment>("BestSolution", "The best GQAP solution."));
       Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the best GQAP solution should be stored."));
@@ -109,39 +142,56 @@
 
     public override IOperation Apply() {
-      DoubleMatrix distances = DistancesParameter.ActualValue;
-      DoubleMatrix weights = WeightsParameter.ActualValue;
-      ItemArray<IntegerVector> assignments = AssignmentParameter.ActualValue;
-      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
-      ResultCollection results = ResultsParameter.ActualValue;
-      bool max = MaximizationParameter.ActualValue.Value;
-      DoubleValue bestKnownQuality = BestKnownQualityParameter.ActualValue;
-
-      var sorted = qualities.Select((x, index) => new { index, x.Value }).OrderBy(x => x.Value).ToArray();
-      if (max) sorted = sorted.Reverse().ToArray();
-      int i = sorted.First().index;
-
-      if (bestKnownQuality == null
-          || max && qualities[i].Value > bestKnownQuality.Value
-          || !max && qualities[i].Value < bestKnownQuality.Value) {
-        // if there isn't a best-known quality or we improved the best-known quality we'll add the current solution as best-known
-        BestKnownQualityParameter.ActualValue = new DoubleValue(qualities[i].Value);
-        BestKnownSolutionParameter.ActualValue = (IntegerVector)assignments[i].Clone();
+      var assignments = AssignmentParameter.ActualValue;
+      var qualities = QualityParameter.ActualValue;
+      var equipmentNames = EquipmentNamesParameter.ActualValue;
+      var locationNames = LocationNamesParameter.ActualValue;
+      var flowDistanceQualities = FlowDistanceQualityParameter.ActualValue;
+      var installationQualities = InstallationQualityParameter.ActualValue;
+      var overbookedCapacities = OverbookedCapacityParameter.ActualValue;
+      var distances = DistancesParameter.ActualValue;
+      var weights = WeightsParameter.ActualValue;
+      var installationCosts = InstallationCostsParameter.ActualValue;
+      var demands = DemandsParameter.ActualValue;
+      var capacities = CapacitiesParameter.ActualValue;
+      var transportationCosts = TransportationCostsParameter.ActualValue;
+      var overbookedCapacityPenalty = OverbookedCapacityPenaltyParameter.ActualValue;
+      var results = ResultsParameter.ActualValue;
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var bestKnownQuality = BestKnownQualityParameter.ActualValue;
+
+      int bestIndex;
+      var tmp = qualities.Select((x, index) => new { Index = index, Value = x.Value });
+      if (maximization) bestIndex = tmp.SelectMax(x => x.Value).Index;
+      else bestIndex = tmp.SelectMin(x => x.Value).Index;
+
+      if (bestKnownQuality == null || HasSolutionImproved(bestKnownQuality.Value, qualities[bestIndex].Value, maximization)) {
+        BestKnownQualityParameter.ActualValue = new DoubleValue(qualities[bestIndex].Value);
+        BestKnownSolutionParameter.ActualValue = (IntegerVector)assignments[bestIndex].Clone();
       }
 
       GQAPAssignment assignment = BestSolutionParameter.ActualValue;
       if (assignment == null) {
-        StringArray equipmentNames = EquipmentNamesParameter.ActualValue;
-        StringArray locationNames = LocationNamesParameter.ActualValue;
-        assignment = new GQAPAssignment(weights, (IntegerVector)assignments[i].Clone(), new DoubleValue(qualities[i].Value), equipmentNames, locationNames);
+        assignment = new GQAPAssignment((IntegerVector)assignments[bestIndex].Clone(), (DoubleValue)qualities[bestIndex].Clone(),
+          equipmentNames, locationNames, distances, weights, installationCosts, demands, capacities, transportationCosts,
+          overbookedCapacityPenalty, flowDistanceQualities[bestIndex], installationQualities[bestIndex], overbookedCapacities[bestIndex]);
         assignment.Distances = distances;
         BestSolutionParameter.ActualValue = assignment;
         results.Add(new Result("Best GQAP Solution", assignment));
       } else {
-        if (max && assignment.Quality.Value < qualities[i].Value ||
-          !max && assignment.Quality.Value > qualities[i].Value) {
+        if (HasSolutionImproved(assignment.Quality.Value, qualities[bestIndex].Value, maximization)) {
+          assignment.Assignment = (IntegerVector)assignments[bestIndex].Clone();
+          assignment.Quality = (DoubleValue)qualities[bestIndex].Clone();
+          assignment.EquipmentNames = equipmentNames;
+          assignment.LocationNames = locationNames;
           assignment.Distances = distances;
           assignment.Weights = weights;
-          assignment.Assignment = (IntegerVector)assignments[i].Clone();
-          assignment.Quality.Value = qualities[i].Value;
+          assignment.InstallationCosts = installationCosts;
+          assignment.Demands = demands;
+          assignment.Capacities = capacities;
+          assignment.TransportationCosts = transportationCosts;
+          assignment.OverbookedCapacityPenalty = overbookedCapacityPenalty;
+          assignment.FlowDistanceQuality = (DoubleValue)flowDistanceQualities[bestIndex].Clone();
+          assignment.InstallationQuality = (DoubleValue)installationQualities[bestIndex].Clone();
+          assignment.OverbookedCapacity = (DoubleValue)overbookedCapacities[bestIndex].Clone();
         }
       }
@@ -149,4 +199,8 @@
       return base.Apply();
     }
+
+    private static bool HasSolutionImproved(double oldQuality, double quality, bool maximization) {
+      return maximization && oldQuality < quality || !maximization && oldQuality > quality;
+    }
   }
 }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs	(revision 7415)
@@ -33,4 +33,48 @@
 
     [Storable]
+    private IntegerVector assignment;
+    public IntegerVector Assignment {
+      get { return assignment; }
+      set {
+        bool changed = (assignment != value);
+        assignment = value;
+        if (changed) OnPropertyChanged("Assignment");
+      }
+    }
+
+    [Storable]
+    private DoubleValue quality;
+    public DoubleValue Quality {
+      get { return quality; }
+      set {
+        bool changed = (quality != value);
+        quality = value;
+        if (changed) OnPropertyChanged("Quality");
+      }
+    }
+
+    [Storable]
+    private StringArray equipmentNames;
+    public StringArray EquipmentNames {
+      get { return equipmentNames; }
+      set {
+        bool changed = (equipmentNames != value);
+        equipmentNames = value;
+        if (changed) OnPropertyChanged("EquipmentNames");
+      }
+    }
+
+    [Storable]
+    private StringArray locationNames;
+    public StringArray LocationNames {
+      get { return locationNames; }
+      set {
+        bool changed = (locationNames != value);
+        locationNames = value;
+        if (changed) OnPropertyChanged("LocationNames");
+      }
+    }
+
+    [Storable]
     private DoubleMatrix distances;
     public DoubleMatrix Distances {
@@ -55,44 +99,88 @@
 
     [Storable]
-    private IntegerVector assignment;
-    public IntegerVector Assignment {
-      get { return assignment; }
-      set {
-        bool changed = (assignment != value);
-        assignment = value;
-        if (changed) OnPropertyChanged("Assignment");
-      }
-    }
-
-    [Storable]
-    private DoubleValue quality;
-    public DoubleValue Quality {
-      get { return quality; }
-      set {
-        bool changed = (quality != value);
-        quality = value;
-        if (changed) OnPropertyChanged("Quality");
-      }
-    }
-
-    [Storable]
-    private StringArray equipmentNames;
-    public StringArray EquipmentNames {
-      get { return equipmentNames; }
-      set {
-        bool changed = (equipmentNames != value);
-        equipmentNames = value;
-        if (changed) OnPropertyChanged("EquipmentNames");
-      }
-    }
-
-    [Storable]
-    private StringArray locationNames;
-    public StringArray LocationNames {
-      get { return locationNames; }
-      set {
-        bool changed = (locationNames != value);
-        locationNames = value;
-        if (changed) OnPropertyChanged("LocationNames");
+    private DoubleMatrix installationCosts;
+    public DoubleMatrix InstallationCosts {
+      get { return installationCosts; }
+      set {
+        bool changed = (installationCosts != value);
+        installationCosts = value;
+        if (changed) OnPropertyChanged("InstallationCosts");
+      }
+    }
+
+    [Storable]
+    private DoubleArray demands;
+    public DoubleArray Demands {
+      get { return demands; }
+      set {
+        bool changed = (demands != value);
+        demands = value;
+        if (changed) OnPropertyChanged("Demands");
+      }
+    }
+
+    [Storable]
+    private DoubleArray capacities;
+    public DoubleArray Capacities {
+      get { return capacities; }
+      set {
+        bool changed = (capacities != value);
+        capacities = value;
+        if (changed) OnPropertyChanged("Capacities");
+      }
+    }
+
+    [Storable]
+    private DoubleValue transportationCosts;
+    public DoubleValue TransportationCosts {
+      get { return transportationCosts; }
+      set {
+        bool changed = (transportationCosts != value);
+        transportationCosts = value;
+        if (changed) OnPropertyChanged("TransportationCosts");
+      }
+    }
+
+    [Storable]
+    private DoubleValue overbookedCapacityPenalty;
+    public DoubleValue OverbookedCapacityPenalty {
+      get { return overbookedCapacityPenalty; }
+      set {
+        bool changed = (overbookedCapacityPenalty != value);
+        overbookedCapacityPenalty = value;
+        if (changed) OnPropertyChanged("OverbookedCapacityPenalty");
+      }
+    }
+
+    [Storable]
+    private DoubleValue flowDistanceQuality;
+    public DoubleValue FlowDistanceQuality {
+      get { return flowDistanceQuality; }
+      set {
+        bool changed = (flowDistanceQuality != value);
+        flowDistanceQuality = value;
+        if (changed) OnPropertyChanged("FlowDistanceQuality");
+      }
+    }
+
+    [Storable]
+    private DoubleValue installationQuality;
+    public DoubleValue InstallationQuality {
+      get { return installationQuality; }
+      set {
+        bool changed = (installationQuality != value);
+        installationQuality = value;
+        if (changed) OnPropertyChanged("InstallationQuality");
+      }
+    }
+
+    [Storable]
+    private DoubleValue overbookedCapacity;
+    public DoubleValue OverbookedCapacity {
+      get { return overbookedCapacity; }
+      set {
+        bool changed = (overbookedCapacity != value);
+        overbookedCapacity = value;
+        if (changed) OnPropertyChanged("OverbookedCapacity");
       }
     }
@@ -102,23 +190,44 @@
     private GQAPAssignment(GQAPAssignment original, Cloner cloner)
       : base(original, cloner) {
-      distances = cloner.Clone(original.distances);
-      weights = cloner.Clone(original.weights);
       assignment = cloner.Clone(original.assignment);
       quality = cloner.Clone(original.quality);
       equipmentNames = cloner.Clone(original.equipmentNames);
       locationNames = cloner.Clone(original.locationNames);
-    }
-    public GQAPAssignment(DoubleMatrix weights, IntegerVector assignment) {
-      this.weights = weights;
+      distances = cloner.Clone(original.distances);
+      weights = cloner.Clone(original.weights);
+      installationCosts = cloner.Clone(original.installationCosts);
+      demands = cloner.Clone(original.demands);
+      capacities = cloner.Clone(original.capacities);
+      transportationCosts = cloner.Clone(original.transportationCosts);
+      overbookedCapacityPenalty = cloner.Clone(original.overbookedCapacityPenalty);
+      flowDistanceQuality = cloner.Clone(original.flowDistanceQuality);
+      installationQuality = cloner.Clone(original.installationQuality);
+      overbookedCapacity = cloner.Clone(original.overbookedCapacity);
+    }
+    public GQAPAssignment(IntegerVector assignment, DoubleValue quality)
+      : base() {
       this.assignment = assignment;
-    }
-    public GQAPAssignment(DoubleMatrix weights, IntegerVector assignment, DoubleValue quality)
-      : this(weights, assignment) {
       this.quality = quality;
     }
-    public GQAPAssignment(DoubleMatrix weights, IntegerVector assignment, DoubleValue quality, StringArray equipmentNames, StringArray locationNames)
-      : this(weights, assignment, quality) {
+    public GQAPAssignment(IntegerVector assignment, DoubleValue quality, StringArray equipmentNames, StringArray locationNames)
+      : this(assignment, quality) {
       this.equipmentNames = equipmentNames;
       this.locationNames = locationNames;
+    }
+    public GQAPAssignment(IntegerVector assignment, DoubleValue quality, StringArray equipmentNames, StringArray locationNames,
+      DoubleMatrix distances, DoubleMatrix weights, DoubleMatrix installationCosts, DoubleArray demands, DoubleArray capacities,
+      DoubleValue transportationCosts, DoubleValue overbookedCapacityPenalty, DoubleValue flowDistanceQuality,
+      DoubleValue installationQuality, DoubleValue overbookedCapacity)
+      : this(assignment, quality, equipmentNames, locationNames) {
+      this.distances = distances;
+      this.weights = weights;
+      this.installationCosts = installationCosts;
+      this.demands = demands;
+      this.capacities = capacities;
+      this.transportationCosts = transportationCosts;
+      this.overbookedCapacityPenalty = overbookedCapacityPenalty;
+      this.flowDistanceQuality = flowDistanceQuality;
+      this.installationQuality = installationQuality;
+      this.overbookedCapacity = overbookedCapacity;
     }
 
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs	(revision 7415)
@@ -68,4 +68,10 @@
       get { return (OptionalValueParameter<IItem>)Parameters["BestKnownSolution"]; }
     }
+    public OptionalValueParameter<StringArray> EquipmentNamesParameter {
+      get { return (OptionalValueParameter<StringArray>)Parameters["EquipmentNames"]; }
+    }
+    public OptionalValueParameter<StringArray> LocationNamesParameter {
+      get { return (OptionalValueParameter<StringArray>)Parameters["LocationNames"]; }
+    }
     #endregion
 
@@ -99,11 +105,16 @@
       set { TransportationCostsParameter.Value.Value = value; }
     }
+    public StringArray EquipmentNames {
+      get { return EquipmentNamesParameter.Value; }
+      set { EquipmentNamesParameter.Value = value; }
+    }
+    public StringArray LocationNames {
+      get { return LocationNamesParameter.Value; }
+      set { LocationNamesParameter.Value = value; }
+    }
     #endregion
 
-    [Storable]
-    private BestGQAPSolutionAnalyzer bestSolutionAnalyzer;
     public BestGQAPSolutionAnalyzer BestSolutionAnalyzer {
-      get { return bestSolutionAnalyzer; }
-      set { bestSolutionAnalyzer = value; }
+      get { return Operators.OfType<BestGQAPSolutionAnalyzer>().First(); }
     }
 
@@ -112,5 +123,4 @@
     private GeneralizedQuadraticAssignmentProblem(GeneralizedQuadraticAssignmentProblem original, Cloner cloner)
       : base(original, cloner) {
-      bestSolutionAnalyzer = cloner.Clone(original.bestSolutionAnalyzer);
       AttachEventHandlers();
     }
@@ -201,9 +211,9 @@
 
     private void InitializeOperators() {
+      Operators.Add(new BestGQAPSolutionAnalyzer());
+      Operators.AddRange(ApplicationManager.Manager.GetInstances<IGQAPOperator>());
       Operators.AddRange(ApplicationManager.Manager.GetInstances<IIntegerVectorOperator>());
-      Operators.AddRange(ApplicationManager.Manager.GetInstances<IGQAPOperator>());
       Operators.RemoveAll(x => x is ISingleObjectiveMoveEvaluator);
       Operators.AddRange(ApplicationManager.Manager.GetInstances<IGQAPMoveEvaluator>());
-      Operators.Add(new BestGQAPSolutionAnalyzer());
       Parameterize();
     }
@@ -276,11 +286,22 @@
 
       if (BestSolutionAnalyzer != null) {
-        BestSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
+        BestSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
         BestSolutionAnalyzer.DistancesParameter.ActualName = DistancesParameter.Name;
         BestSolutionAnalyzer.WeightsParameter.ActualName = WeightsParameter.Name;
+        BestSolutionAnalyzer.InstallationCostsParameter.ActualName = InstallationCostsParameter.Name;
+        BestSolutionAnalyzer.DemandsParameter.ActualName = DemandsParameter.Name;
+        BestSolutionAnalyzer.CapacitiesParameter.ActualName = CapacitiesParameter.Name;
+        BestSolutionAnalyzer.TransportationCostsParameter.ActualName = TransportationCostsParameter.Name;
+        BestSolutionAnalyzer.OverbookedCapacityPenaltyParameter.ActualName = OverbookedCapacityPenaltyParameter.Name;
         BestSolutionAnalyzer.AssignmentParameter.ActualName = SolutionCreator.AssignmentParameter.ActualName;
+        BestSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
+        BestSolutionAnalyzer.FlowDistanceQualityParameter.ActualName = Evaluator.FlowDistanceQualityParameter.ActualName;
+        BestSolutionAnalyzer.InstallationQualityParameter.ActualName = Evaluator.InstallationQualityParameter.ActualName;
+        BestSolutionAnalyzer.OverbookedCapacityParameter.ActualName = Evaluator.OverbookedCapacityParameter.ActualName;
         BestSolutionAnalyzer.ResultsParameter.ActualName = "Results";
         BestSolutionAnalyzer.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
-        BestSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
+        BestSolutionAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
+        BestSolutionAnalyzer.EquipmentNamesParameter.ActualName = EquipmentNamesParameter.Name;
+        BestSolutionAnalyzer.LocationNamesParameter.ActualName = LocationNamesParameter.Name;
       }
     }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs	(revision 7414)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs	(revision 7415)
@@ -60,5 +60,5 @@
       while (tries < maxTries) {
         assignment.Clear();
-        capacities.Select((v, i) => slack[i] = v).Enumerate();
+        slack = capacities.Select((v, i) => new { Index = i, Value = v }).ToDictionary(x => x.Index, y => y.Value);
         HashSet<int> CF = new HashSet<int>(), // set of chosen facilities / equipments
           T = new HashSet<int>(), // set of facilities / equpiments that can be assigned to the set of chosen locations (CL)
