source: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Views/3.3/GQAPAssignmentView.cs @ 15510

Last change on this file since 15510 was 15510, checked in by abeham, 21 months ago

#1614:

  • Fixed bugs in view
  • Made Evaluation object immutable
  • Fixed bug in Analyze
  • Fixed operators
File size: 11.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 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.Image = VSImageLibrary.Refresh;
48    }
49
50    #region Register Content Events
51    protected override void DeregisterContentEvents() {
52      Content.PropertyChanged -= new PropertyChangedEventHandler(Content_PropertyChanged);
53      base.DeregisterContentEvents();
54    }
55    protected override void RegisterContentEvents() {
56      base.RegisterContentEvents();
57      Content.PropertyChanged += new PropertyChangedEventHandler(Content_PropertyChanged);
58    }
59    #endregion
60
61    protected override void OnContentChanged() {
62      base.OnContentChanged();
63      UpdateEvaluation();
64      UpdateAssignment();
65      if (Content != null) assignmentView.Content = Content.Assignment;
66      else assignmentView.Content = null;
67    }
68
69    protected override void SetEnabledStateOfControls() {
70      base.SetEnabledStateOfControls();
71    }
72
73    #region Content Event Handlers
74    private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
75      switch (e.PropertyName) {
76        case nameof(Content.Evaluation): UpdateEvaluation(); break;
77        case nameof(Content.Assignment): UpdateAssignment(); break;
78        case nameof(Content.ProblemInstance): UpdateEvaluation(); UpdateAssignment(); break;
79        default: break;
80      }
81    }
82
83    private void Content_Assignment_ToStringChanged(object sender, EventArgs e) {
84      UpdateAssignment();
85    }
86    #endregion
87
88    #region Event Handlers
89    private void assignmentTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
90      if (Content != null) {
91        assignmentTreeView.BeginUpdate();
92        try {
93          if (assignmentTreeView.SelectedNode == null) {
94            ColorByInstallationCosts();
95          } else {
96            var equipmentNode = (assignmentTreeView.SelectedNode as EquipmentNode);
97            if (equipmentNode != null) {
98              ColorByWeight(equipmentNode);
99            }
100            var locationNode = (assignmentTreeView.SelectedNode as LocationNode);
101            if (locationNode != null) {
102              ColorByWeight(locationNode);
103            }
104          }
105        } finally { assignmentTreeView.EndUpdate(); }
106      }
107    }
108
109    private void assignmentTreeView_MouseUp(object sender, MouseEventArgs e) {
110      var hit = assignmentTreeView.HitTest(e.X, e.Y);
111      if (hit.Node == null || hit.Location == TreeViewHitTestLocations.None || hit.Location == TreeViewHitTestLocations.RightOfLabel) {
112        assignmentTreeView.SelectedNode = null;
113        ColorByInstallationCosts();
114      }
115    }
116    #endregion
117
118    #region Helpers
119    private void UpdateEvaluation() {
120      if (InvokeRequired) Invoke((Action)UpdateEvaluation);
121      else {
122        if (Content == null) {
123          qualityLabel.Text = "-";
124          flowDistanceQualityLabel.Text = "-";
125          installationQualityLabel.Text = "-";
126          overbookedCapacityLabel.Text = "-";
127        } else {
128          qualityLabel.Text = Content.ProblemInstance.ToSingleObjective(Content.Evaluation).ToString();
129          flowDistanceQualityLabel.Text = Content.Evaluation.FlowCosts.ToString();
130          installationQualityLabel.Text = Content.Evaluation.InstallationCosts.ToString();
131          overbookedCapacityLabel.Text = Content.Evaluation.ExcessDemand.ToString();
132        }
133      }
134    }
135
136    private void UpdateAssignment() {
137      if (InvokeRequired) Invoke((Action)UpdateAssignment);
138      else {
139        assignmentTreeView.Nodes.Clear();
140        if (Content != null) {
141          IntegerVector assignment = Content.Assignment;
142          Dictionary<int, TreeNode> locationNodes = new Dictionary<int, TreeNode>();
143          for (int i = 0; i < assignment.Length; i++) {
144            if (!locationNodes.ContainsKey(assignment[i])) {
145              string locationName = assignment[i].ToString();
146              if (Content.ProblemInstance.LocationNames != null && Content.ProblemInstance.LocationNames.Length > assignment[i])
147                locationName = Content.ProblemInstance.LocationNames[assignment[i]];
148              locationNodes.Add(assignment[i], new LocationNode(assignment[i], locationName));
149            }
150            string equipmentName = i.ToString();
151            if (Content.ProblemInstance.EquipmentNames != null && Content.ProblemInstance.EquipmentNames.Length > i)
152              equipmentName = Content.ProblemInstance.EquipmentNames[i];
153            locationNodes[assignment[i]].Nodes.Add(new EquipmentNode(i, equipmentName));
154          }
155
156          assignmentTreeView.BeginUpdate();
157          try {
158            foreach (var node in locationNodes.OrderBy(x => x.Key).Select(x => x.Value)) {
159              assignmentTreeView.Nodes.Add(node);
160              node.Expand();
161            }
162            ColorByInstallationCosts();
163          } finally { assignmentTreeView.EndUpdate(); }
164        }
165      }
166    }
167
168    private void ColorByInstallationCosts() {
169      var installationCosts = new Dictionary<EquipmentNode, double>();
170      foreach (var node in GetAllSubNodes(assignmentTreeView.Nodes).OfType<EquipmentNode>()) {
171        int location = Content.Assignment[node.Equipment];
172        installationCosts[node] = Content.ProblemInstance.InstallationCosts[node.Equipment, location];
173      }
174      double max = installationCosts.Values.Max();
175      foreach (var kvp in installationCosts) {
176        if (max == 0) {
177          kvp.Key.BackColor = assignmentTreeView.BackColor;
178          kvp.Key.ForeColor = assignmentTreeView.ForeColor;
179        } else {
180          int colorComponent = (int)(255 * Math.Pow((max - kvp.Value) / max, 2));
181          kvp.Key.BackColor = Color.FromArgb(255, colorComponent, colorComponent);
182          if (kvp.Key.BackColor.GetBrightness() < BrightnessLevel) kvp.Key.ForeColor = Color.White;
183          else kvp.Key.ForeColor = Color.Black;
184        }
185      }
186    }
187
188    private void ColorByWeight(EquipmentNode selectedNode) {
189      int equipment = selectedNode.Equipment;
190      double rowSum = 0, colSum = 0;
191      for (int i = 0; i < Content.ProblemInstance.Weights.Columns; i++)
192        if (i != equipment) rowSum += Content.ProblemInstance.Weights[equipment, i];
193      for (int i = 0; i < Content.ProblemInstance.Weights.Rows; i++)
194        if (i != equipment) colSum += Content.ProblemInstance.Weights[i, equipment];
195
196      var otherEquipments = GetAllSubNodes(assignmentTreeView.Nodes)
197        .OfType<EquipmentNode>()
198        .Where(x => x != selectedNode);
199
200      selectedNode.BackColor = assignmentTreeView.BackColor;
201      selectedNode.ForeColor = assignmentTreeView.ForeColor;
202      foreach (var other in otherEquipments) {
203        if (rowSum == 0 && colSum == 0) {
204          other.BackColor = assignmentTreeView.BackColor;
205          other.ForeColor = assignmentTreeView.ForeColor;
206        } else {
207          double rowInvProportion = rowSum == 0 ? 1.0 : (rowSum - Content.ProblemInstance.Weights[equipment, other.Equipment]) / rowSum;
208          double colInvProportion = colSum == 0 ? 1.0 : (colSum - Content.ProblemInstance.Weights[other.Equipment, equipment]) / colSum;
209          int colorComponent = (int)(255 * Math.Pow(Math.Min(rowInvProportion, colInvProportion), 2));
210          other.BackColor = Color.FromArgb(colorComponent, 255, colorComponent);
211          if (other.BackColor.GetBrightness() < BrightnessLevel) other.ForeColor = Color.White;
212          else other.ForeColor = Color.Black;
213        }
214      }
215    }
216
217    private void ColorByWeight(LocationNode selectedNode) {
218      var equipments = new HashSet<int>(Content.Assignment.Select((v, i) => new { Index = i, Value = v })
219        .Where(x => x.Value == selectedNode.Location).Select(x => x.Index));
220      var rowSums = new Dictionary<int, double>(equipments.Count);
221      var colSums = new Dictionary<int, double>(equipments.Count);
222      foreach (var e in equipments) {
223        rowSums[e] = 0;
224        colSums[e] = 0;
225        for (int i = 0; i < Content.ProblemInstance.Weights.Columns; i++) {
226          if (!equipments.Contains(i)) rowSums[e] += Content.ProblemInstance.Weights[e, i];
227          if (!equipments.Contains(i)) colSums[e] += Content.ProblemInstance.Weights[i, e];
228        }
229      }
230      var equipmentNodes = GetAllSubNodes(assignmentTreeView.Nodes)
231        .OfType<EquipmentNode>();
232
233      var relevantEquipments = new HashSet<int>(equipments.Where(x => rowSums[x] > 0 || colSums[x] > 0));
234      foreach (var other in equipmentNodes) {
235        if (!relevantEquipments.Any() || equipments.Contains(other.Equipment)) {
236          other.BackColor = assignmentTreeView.BackColor;
237          other.ForeColor = assignmentTreeView.ForeColor;
238        } else {
239          double rowInvProportion = relevantEquipments.Min(x => rowSums[x] == 0 ? 1.0 : (rowSums[x] - Content.ProblemInstance.Weights[x, other.Equipment]) / rowSums[x]);
240          double colInvProportion = relevantEquipments.Min(x => colSums[x] == 0 ? 1.0 : (colSums[x] - Content.ProblemInstance.Weights[other.Equipment, x]) / colSums[x]);
241          int colorComponent = (int)(255 * Math.Pow(Math.Min(rowInvProportion, colInvProportion), 2));
242          other.BackColor = Color.FromArgb(colorComponent, 255, colorComponent);
243          if (other.BackColor.GetBrightness() < BrightnessLevel) other.ForeColor = Color.White;
244          else other.ForeColor = Color.Black;
245        }
246      }
247    }
248
249    private IEnumerable<TreeNode> GetAllSubNodes(TreeNodeCollection nodes) {
250      foreach (TreeNode node in nodes) {
251        yield return node;
252        foreach (TreeNode subNode in GetAllSubNodes(node.Nodes))
253          yield return subNode;
254      }
255    }
256    #endregion
257
258    #region Helper Classes
259    private class LocationNode : TreeNode {
260      public int Location { get; set; }
261
262      public LocationNode() : base() { }
263      public LocationNode(int location, string name)
264        : base(name) {
265        Location = location;
266      }
267    }
268
269    private class EquipmentNode : TreeNode {
270      public int Equipment { get; set; }
271
272      public EquipmentNode() : base() { }
273      public EquipmentNode(int equipment, string name)
274        : base(name) {
275        Equipment = equipment;
276      }
277    }
278    #endregion
279
280    private void recalculateButton_Click(object sender, EventArgs e) {
281      Content.Evaluation = Content.ProblemInstance.Evaluate(Content.Assignment);
282    }
283  }
284}
Note: See TracBrowser for help on using the repository browser.