source: branches/2936_GQAPIntegration/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.cs @ 16077

Last change on this file since 16077 was 16077, checked in by abeham, 12 months ago

#2936: Added integration branch

File size: 12.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Common.Resources;
29using HeuristicLab.Core.Views;
30using HeuristicLab.Encodings.IntegerVectorEncoding;
31using HeuristicLab.MainForm;
32using HeuristicLab.MainForm.WindowsForms;
33
34namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views {
35  [View("GQAPAssignmentView")]
36  [Content(typeof(GQAPAssignment), IsDefaultView = true)]
37  public partial class GQAPAssignmentView : ItemView {
38    private static readonly double BrightnessLevel = 0.5;
39
40    public new GQAPAssignment Content {
41      get { return (GQAPAssignment)base.Content; }
42      set { base.Content = value; }
43    }
44
45    public GQAPAssignmentView() {
46      InitializeComponent();
47      recalculateButton.Text = string.Empty;
48      recalculateButton.Image = VSImageLibrary.Refresh;
49    }
50
51    #region Register Content Events
52    protected override void DeregisterContentEvents() {
53      DeregisterSolutionEvents();
54      Content.PropertyChanged -= Content_PropertyChanged;
55      base.DeregisterContentEvents();
56    }
57    protected override void RegisterContentEvents() {
58      base.RegisterContentEvents();
59      Content.PropertyChanged += Content_PropertyChanged;
60      RegisterSolutionEvents();
61    }
62
63    private void DeregisterSolutionEvents() {
64      if (Content.Solution != null) Content.Solution.PropertyChanged -= Content_SolutionPropertyChanged;
65    }
66    private void RegisterSolutionEvents() {
67      if (Content.Solution != null) Content.Solution.PropertyChanged += Content_SolutionPropertyChanged;
68    }
69    #endregion
70
71    protected override void OnContentChanged() {
72      base.OnContentChanged();
73      UpdateEvaluation();
74      UpdateAssignment();
75      if (Content != null && Content.Solution != null) assignmentView.Content = Content.Solution.Assignment;
76      else assignmentView.Content = null;
77    }
78
79    protected override void SetEnabledStateOfControls() {
80      base.SetEnabledStateOfControls();
81      recalculateButton.Enabled = Content != null && Content.Solution != null && !Locked && !ReadOnly;
82    }
83
84    #region Content Event Handlers
85    private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
86      switch (e.PropertyName) {
87        case nameof(Content.Solution): RegisterSolutionEvents(); UpdateEvaluation(); UpdateAssignment(); break;
88        case nameof(Content.ProblemInstance): UpdateEvaluation(); UpdateAssignment(); break;
89        default: break;
90      }
91      SetEnabledStateOfControls();
92    }
93
94    private void Content_SolutionPropertyChanged(object sender, PropertyChangedEventArgs e) {
95      switch (e.PropertyName) {
96        case nameof(Content.Solution.Assignment): UpdateAssignment(); break;
97        case nameof(Content.Solution.Evaluation): UpdateEvaluation(); break;
98        default: break;
99      }
100    }
101
102    private void Content_Assignment_ToStringChanged(object sender, EventArgs e) {
103      UpdateAssignment();
104    }
105    #endregion
106
107    #region Event Handlers
108    private void assignmentTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
109      if (Content != null && Content.Solution != null) {
110        assignmentTreeView.BeginUpdate();
111        try {
112          if (assignmentTreeView.SelectedNode == null) {
113            ColorByInstallationCosts();
114          } else {
115            var equipmentNode = (assignmentTreeView.SelectedNode as EquipmentNode);
116            if (equipmentNode != null) {
117              ColorByWeight(equipmentNode);
118            }
119            var locationNode = (assignmentTreeView.SelectedNode as LocationNode);
120            if (locationNode != null) {
121              ColorByWeight(locationNode);
122            }
123          }
124        } finally { assignmentTreeView.EndUpdate(); }
125      }
126    }
127
128    private void assignmentTreeView_MouseUp(object sender, MouseEventArgs e) {
129      var hit = assignmentTreeView.HitTest(e.X, e.Y);
130      if (hit.Node == null || hit.Location == TreeViewHitTestLocations.None || hit.Location == TreeViewHitTestLocations.RightOfLabel) {
131        assignmentTreeView.SelectedNode = null;
132        ColorByInstallationCosts();
133      }
134    }
135    #endregion
136
137    #region Helpers
138    private void UpdateEvaluation() {
139      if (InvokeRequired) Invoke((Action)UpdateEvaluation);
140      else {
141        if (Content == null || Content.Solution == null) {
142          qualityLabel.Text = "-";
143          flowDistanceQualityLabel.Text = "-";
144          installationQualityLabel.Text = "-";
145          overbookedCapacityLabel.Text = "-";
146        } else {
147          qualityLabel.Text = Content.ProblemInstance.ToSingleObjective(Content.Solution.Evaluation).ToString();
148          flowDistanceQualityLabel.Text = Content.Solution.Evaluation.FlowCosts.ToString();
149          installationQualityLabel.Text = Content.Solution.Evaluation.InstallationCosts.ToString();
150          overbookedCapacityLabel.Text = Content.Solution.Evaluation.ExcessDemand.ToString();
151        }
152      }
153    }
154
155    private void UpdateAssignment() {
156      if (InvokeRequired) Invoke((Action)UpdateAssignment);
157      else {
158        assignmentTreeView.Nodes.Clear();
159        if (Content != null && Content.Solution != null) {
160          IntegerVector assignment = Content.Solution.Assignment;
161          Dictionary<int, TreeNode> locationNodes = new Dictionary<int, TreeNode>();
162          for (int i = 0; i < assignment.Length; i++) {
163            if (!locationNodes.ContainsKey(assignment[i])) {
164              string locationName = assignment[i].ToString();
165              if (Content.ProblemInstance.LocationNames != null && Content.ProblemInstance.LocationNames.Length > assignment[i])
166                locationName = Content.ProblemInstance.LocationNames[assignment[i]];
167              locationNodes.Add(assignment[i], new LocationNode(assignment[i], locationName));
168            }
169            string equipmentName = i.ToString();
170            if (Content.ProblemInstance.EquipmentNames != null && Content.ProblemInstance.EquipmentNames.Length > i)
171              equipmentName = Content.ProblemInstance.EquipmentNames[i];
172            locationNodes[assignment[i]].Nodes.Add(new EquipmentNode(i, equipmentName));
173          }
174
175          assignmentTreeView.BeginUpdate();
176          try {
177            foreach (var node in locationNodes.OrderBy(x => x.Key).Select(x => x.Value)) {
178              assignmentTreeView.Nodes.Add(node);
179              node.Expand();
180            }
181            ColorByInstallationCosts();
182          } finally { assignmentTreeView.EndUpdate(); }
183        }
184      }
185    }
186
187    private void ColorByInstallationCosts() {
188      var installationCosts = new Dictionary<EquipmentNode, double>();
189      foreach (var node in GetAllSubNodes(assignmentTreeView.Nodes).OfType<EquipmentNode>()) {
190        int location = Content.Solution.Assignment[node.Equipment];
191        installationCosts[node] = Content.ProblemInstance.InstallationCosts[node.Equipment, location];
192      }
193      double max = installationCosts.Values.Max();
194      foreach (var kvp in installationCosts) {
195        if (max == 0) {
196          kvp.Key.BackColor = assignmentTreeView.BackColor;
197          kvp.Key.ForeColor = assignmentTreeView.ForeColor;
198        } else {
199          int colorComponent = (int)(255 * Math.Pow((max - kvp.Value) / max, 2));
200          kvp.Key.BackColor = Color.FromArgb(255, colorComponent, colorComponent);
201          if (kvp.Key.BackColor.GetBrightness() < BrightnessLevel) kvp.Key.ForeColor = Color.White;
202          else kvp.Key.ForeColor = Color.Black;
203        }
204      }
205    }
206
207    private void ColorByWeight(EquipmentNode selectedNode) {
208      int equipment = selectedNode.Equipment;
209      double rowSum = 0, colSum = 0;
210      for (int i = 0; i < Content.ProblemInstance.Weights.Columns; i++)
211        if (i != equipment) rowSum += Content.ProblemInstance.Weights[equipment, i];
212      for (int i = 0; i < Content.ProblemInstance.Weights.Rows; i++)
213        if (i != equipment) colSum += Content.ProblemInstance.Weights[i, equipment];
214
215      var otherEquipments = GetAllSubNodes(assignmentTreeView.Nodes)
216        .OfType<EquipmentNode>()
217        .Where(x => x != selectedNode);
218
219      selectedNode.BackColor = assignmentTreeView.BackColor;
220      selectedNode.ForeColor = assignmentTreeView.ForeColor;
221      foreach (var other in otherEquipments) {
222        if (rowSum == 0 && colSum == 0) {
223          other.BackColor = assignmentTreeView.BackColor;
224          other.ForeColor = assignmentTreeView.ForeColor;
225        } else {
226          double rowInvProportion = rowSum == 0 ? 1.0 : (rowSum - Content.ProblemInstance.Weights[equipment, other.Equipment]) / rowSum;
227          double colInvProportion = colSum == 0 ? 1.0 : (colSum - Content.ProblemInstance.Weights[other.Equipment, equipment]) / colSum;
228          int colorComponent = (int)(255 * Math.Pow(Math.Min(rowInvProportion, colInvProportion), 2));
229          other.BackColor = Color.FromArgb(colorComponent, 255, colorComponent);
230          if (other.BackColor.GetBrightness() < BrightnessLevel) other.ForeColor = Color.White;
231          else other.ForeColor = Color.Black;
232        }
233      }
234    }
235
236    private void ColorByWeight(LocationNode selectedNode) {
237      var equipments = new HashSet<int>(Content.Solution.Assignment.Select((v, i) => new { Index = i, Value = v })
238        .Where(x => x.Value == selectedNode.Location).Select(x => x.Index));
239      var rowSums = new Dictionary<int, double>(equipments.Count);
240      var colSums = new Dictionary<int, double>(equipments.Count);
241      foreach (var e in equipments) {
242        rowSums[e] = 0;
243        colSums[e] = 0;
244        for (int i = 0; i < Content.ProblemInstance.Weights.Columns; i++) {
245          if (!equipments.Contains(i)) rowSums[e] += Content.ProblemInstance.Weights[e, i];
246          if (!equipments.Contains(i)) colSums[e] += Content.ProblemInstance.Weights[i, e];
247        }
248      }
249      var equipmentNodes = GetAllSubNodes(assignmentTreeView.Nodes)
250        .OfType<EquipmentNode>();
251
252      var relevantEquipments = new HashSet<int>(equipments.Where(x => rowSums[x] > 0 || colSums[x] > 0));
253      foreach (var other in equipmentNodes) {
254        if (!relevantEquipments.Any() || equipments.Contains(other.Equipment)) {
255          other.BackColor = assignmentTreeView.BackColor;
256          other.ForeColor = assignmentTreeView.ForeColor;
257        } else {
258          double rowInvProportion = relevantEquipments.Min(x => rowSums[x] == 0 ? 1.0 : (rowSums[x] - Content.ProblemInstance.Weights[x, other.Equipment]) / rowSums[x]);
259          double colInvProportion = relevantEquipments.Min(x => colSums[x] == 0 ? 1.0 : (colSums[x] - Content.ProblemInstance.Weights[other.Equipment, x]) / colSums[x]);
260          int colorComponent = (int)(255 * Math.Pow(Math.Min(rowInvProportion, colInvProportion), 2));
261          other.BackColor = Color.FromArgb(colorComponent, 255, colorComponent);
262          if (other.BackColor.GetBrightness() < BrightnessLevel) other.ForeColor = Color.White;
263          else other.ForeColor = Color.Black;
264        }
265      }
266    }
267
268    private IEnumerable<TreeNode> GetAllSubNodes(TreeNodeCollection nodes) {
269      foreach (TreeNode node in nodes) {
270        yield return node;
271        foreach (TreeNode subNode in GetAllSubNodes(node.Nodes))
272          yield return subNode;
273      }
274    }
275    #endregion
276
277    #region Helper Classes
278    private class LocationNode : TreeNode {
279      public int Location { get; set; }
280
281      public LocationNode() : base() { }
282      public LocationNode(int location, string name)
283        : base(name) {
284        Location = location;
285      }
286    }
287
288    private class EquipmentNode : TreeNode {
289      public int Equipment { get; set; }
290
291      public EquipmentNode() : base() { }
292      public EquipmentNode(int equipment, string name)
293        : base(name) {
294        Equipment = equipment;
295      }
296    }
297    #endregion
298
299    private void recalculateButton_Click(object sender, EventArgs e) {
300      Content.Solution.Evaluation = Content.ProblemInstance.Evaluate(Content.Solution.Assignment);
301    }
302  }
303}
Note: See TracBrowser for help on using the repository browser.