Free cookie consent management tool by TermsFeed Policy Generator

source: branches/QAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/QAPView.cs @ 5855

Last change on this file since 5855 was 5855, checked in by abeham, 13 years ago

#1330

  • Fixed calculation of normalized stress value
  • Fixed a few bugs
File size: 19.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.Drawing;
24using System.Drawing.Drawing2D;
25using System.Drawing.Text;
26using System.Globalization;
27using System.Windows.Forms;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.PermutationEncoding;
32
33namespace HeuristicLab.Problems.QuadraticAssignment.Views {
34  public partial class QAPView : UserControl {
35    private Bitmap bitmap;
36    private Bitmap defaultBitmap;
37
38    #region Properties
39    private DoubleMatrix distances;
40    public DoubleMatrix Distances {
41      get { return distances; }
42      set {
43        DeregisterDistancesEvents();
44        distances = value;
45        RegisterDistancesEvents();
46        OnRedraw();
47      }
48    }
49
50    private DoubleMatrix weights;
51    public DoubleMatrix Weights {
52      get { return weights; }
53      set {
54        DeregisterWeightsEvents();
55        weights = value;
56        RegisterWeightsEvents();
57        OnRedraw();
58      }
59    }
60
61    private Permutation assignment;
62    public Permutation Assignment {
63      get { return assignment; }
64      set {
65        DeregisterAssignmentEvents();
66        assignment = value;
67        RegisterAssignmentEvents();
68        OnRedraw();
69      }
70    }
71    #endregion
72
73    #region Event Handling
74    private void DeregisterDistancesEvents() {
75      if (Distances != null) {
76        Distances.Reset -= new EventHandler(Redraw);
77        Distances.RowsChanged -= new EventHandler(Redraw);
78        Distances.ColumnsChanged -= new EventHandler(Redraw);
79        Distances.ItemChanged -= new EventHandler<EventArgs<int, int>>(Redraw);
80      }
81    }
82
83    private void RegisterDistancesEvents() {
84      if (Distances != null) {
85        Distances.Reset += new EventHandler(Redraw);
86        Distances.RowsChanged += new EventHandler(Redraw);
87        Distances.ColumnsChanged += new EventHandler(Redraw);
88        Distances.ItemChanged += new EventHandler<EventArgs<int, int>>(Redraw);
89      }
90    }
91
92    private void DeregisterWeightsEvents() {
93      if (Weights != null) {
94        Weights.Reset -= new EventHandler(Redraw);
95        Weights.RowsChanged -= new EventHandler(Redraw);
96        Weights.ColumnsChanged -= new EventHandler(Redraw);
97        Weights.ItemChanged -= new EventHandler<EventArgs<int, int>>(Redraw);
98      }
99    }
100
101    private void RegisterWeightsEvents() {
102      if (Weights != null) {
103        Weights.Reset += new EventHandler(Redraw);
104        Weights.RowsChanged += new EventHandler(Redraw);
105        Weights.ColumnsChanged += new EventHandler(Redraw);
106        Weights.ItemChanged += new EventHandler<EventArgs<int, int>>(Redraw);
107      }
108    }
109
110    private void DeregisterAssignmentEvents() {
111      if (Assignment != null) {
112        Assignment.Reset -= new EventHandler(Redraw);
113        Assignment.ItemChanged -= new EventHandler<EventArgs<int>>(Redraw);
114      }
115    }
116
117    private void RegisterAssignmentEvents() {
118      if (Assignment != null) {
119        Assignment.Reset += new EventHandler(Redraw);
120        Assignment.ItemChanged += new EventHandler<EventArgs<int>>(Redraw);
121      }
122    }
123
124    private void Redraw(object sender, EventArgs e) {
125      if (sender is RadioButton && !((RadioButton)sender).Checked)
126        return;
127      OnRedraw();
128    }
129
130    private void Redraw(object sender, EventArgs<int, int> e) {
131      OnRedraw();
132    }
133
134    private void pictureBox_SizeChanged(object sender, EventArgs e) {
135      SetupDefaultBitmap();
136      OnRedraw();
137    }
138    #endregion
139
140    public QAPView() {
141      InitializeComponent();
142      SetupDefaultBitmap();
143    }
144
145    private void SetupDefaultBitmap() {
146      if (defaultBitmap != null) {
147        defaultBitmap.Dispose();
148        defaultBitmap = null;
149      }
150      if (pictureBox.Width > 0 && pictureBox.Height > 0) {
151        defaultBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
152        WriteCenteredTextToBitmap(ref defaultBitmap, "No visualization available");
153      }
154    }
155
156    private void WriteCenteredTextToBitmap(ref Bitmap bitmap, string text) {
157      if (bitmap == null) return;
158      using (Graphics g = Graphics.FromImage(bitmap)) {
159        g.TextRenderingHint = TextRenderingHint.AntiAlias;
160        g.SmoothingMode = SmoothingMode.AntiAlias;
161
162        SizeF strSize = g.MeasureString(text, Font);
163        g.DrawString(text, Font, Brushes.Black, (float)(pictureBox.Width - strSize.Width) / 2.0f, (float)(pictureBox.Height - strSize.Height) / 2.0f);
164      }
165    }
166
167    private void OnRedraw() {
168      if (InvokeRequired) {
169        Invoke((Action)OnRedraw, null);
170      } else {
171        GenerateImage();
172      }
173    }
174
175    private void GenerateImage() {
176      if (pictureBox.Width > 0 && pictureBox.Height > 0) {
177        Bitmap newBitmap = null;
178        stressLabel.Text = "-";
179        if (distancesRadioButton.Checked && Distances != null && Distances.Rows > 0
180          && Distances.Rows == Distances.Columns) {
181          if (Distances.Rows > 30) {
182            newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
183            WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
184          } else newBitmap = GenerateDistanceImage();
185        } else if (weightsRadioButton.Checked && Weights != null && Weights.Rows > 0
186          && Weights.Rows == Weights.Columns) {
187          if (Weights.Rows > 30) {
188            newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
189            WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
190          } else newBitmap = GenerateWeightsImage();
191        } else if (assignmentRadioButton.Checked
192          && Assignment != null && Assignment.Length > 0
193          && Weights != null && Weights.Rows > 0
194          && Distances != null && Distances.Rows > 0
195          && Weights.Rows == Weights.Columns
196          && Distances.Rows == Distances.Columns
197          && Assignment.Length == Weights.Rows
198          && Assignment.Length == Distances.Rows
199          && Assignment.Validate()) {
200          if (Assignment.Length > 30) {
201            newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
202            WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
203          } else newBitmap = GenerateAssignmentImage();
204        }
205
206        pictureBox.Image = newBitmap != null ? newBitmap : defaultBitmap;
207        if (bitmap != null) bitmap.Dispose();
208        if (newBitmap != null) bitmap = newBitmap;
209        else bitmap = null;
210      }
211    }
212
213    #region Draw distances
214    private Bitmap GenerateDistanceImage() {
215      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
216        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
217
218        for (int i = 0; i < distances.Rows; i++) {
219          for (int j = i + 1; j < distances.Rows; j++)
220            if (distances[i, j] != distances[j, i]) {
221              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
222              return newBitmap;
223            }
224        }
225
226        double stress;
227        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
228        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
229        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
230        double maxDistance = double.MinValue;
231        for (int i = 0; i < coordinates.Rows; i++) {
232          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
233          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
234          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
235          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
236
237          for (int j = i + 1; j < coordinates.Rows; j++) {
238            if (distances[i, j] > maxDistance) maxDistance = distances[i, j];
239            if (distances[j, i] > maxDistance) maxDistance = distances[j, i];
240          }
241        }
242
243        int border = 20;
244        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
245        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
246
247        Point[] points = new Point[coordinates.Rows];
248        for (int i = 0; i < coordinates.Rows; i++)
249          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
250                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
251
252        Random rand = new Random();
253        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
254          graphics.SmoothingMode = SmoothingMode.AntiAlias;
255          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
256          graphics.DrawString("Showing locations spaced out according to their distances", Font, Brushes.Black, 5, 2);
257
258          for (int i = 0; i < coordinates.Rows - 1; i++) {
259            for (int j = i + 1; j < coordinates.Rows; j++) {
260              Point start = points[i], end = points[j];
261              string caption = String.Empty;
262              double d = Math.Max(distances[i, j], distances[j, i]);
263              float width = (float)Math.Ceiling(5.0 * d / maxDistance);
264              if (d > 0) {
265                graphics.DrawLine(new Pen(Color.IndianRed, width), start, end);
266                if (distances[i, j] != distances[j, i])
267                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat)
268                    + " / " + distances[j, i].ToString(CultureInfo.InvariantCulture.NumberFormat);
269                else
270                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat);
271              }
272              if (!String.IsNullOrEmpty(caption)) {
273                double r = rand.NextDouble();
274                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
275                float x = (float)(start.X + (end.X - start.X) * r + 5);
276                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
277                graphics.DrawString(caption, Font, Brushes.Black, x, y);
278              }
279            }
280          }
281
282          for (int i = 0; i < points.Length; i++) {
283            Point p = new Point(points[i].X - 3, points[i].Y - 3);
284            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
285            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
286          }
287        }
288        return newBitmap;
289      }
290      return null;
291    }
292    #endregion
293
294    #region Draw weights
295    private Bitmap GenerateWeightsImage() {
296      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
297        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
298
299        double maxWeight = double.MinValue;
300        for (int i = 0; i < weights.Rows; i++)
301          for (int j = i + 1; j < weights.Rows; j++) {
302            if (weights[i, j] > maxWeight)
303              maxWeight = weights[i, j] + weights[j, i];
304
305            if (weights[i, j] != weights[j, i]) {
306              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
307              return newBitmap;
308            }
309          }
310
311        DoubleMatrix distances = new DoubleMatrix(weights.Rows, weights.Columns);
312        for (int i = 0; i < distances.Rows; i++)
313          for (int j = 0; j < distances.Columns; j++) {
314            distances[i, j] = maxWeight + 1 - weights[i, j];
315          }
316
317        double stress;
318        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
319        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
320        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
321        for (int i = 0; i < coordinates.Rows; i++) {
322          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
323          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
324          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
325          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
326        }
327
328        int border = 20;
329        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
330        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
331
332        Point[] points = new Point[coordinates.Rows];
333        for (int i = 0; i < coordinates.Rows; i++)
334          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
335                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
336
337        Random rand = new Random();
338        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
339          graphics.SmoothingMode = SmoothingMode.AntiAlias;
340          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
341          graphics.DrawString("Showing facilities spaced out according to their weights", Font, Brushes.Black, 5, 2);
342
343          for (int i = 0; i < coordinates.Rows - 1; i++) {
344            for (int j = i + 1; j < coordinates.Rows; j++) {
345              Point start = points[i], end = points[j];
346              string caption = String.Empty;
347              double d = Math.Max(distances[i, j], distances[j, i]);
348              double w = weights[i, j];
349              if (w > 0) {
350                float width = (float)Math.Ceiling(3.0 * w / maxWeight);
351                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
352                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
353              }
354              if (!String.IsNullOrEmpty(caption)) {
355                double r = rand.NextDouble();
356                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
357                float x = (float)(start.X + (end.X - start.X) * r + 5);
358                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
359                graphics.DrawString(caption, Font, Brushes.Black, x, y);
360              }
361            }
362          }
363          for (int i = 0; i < points.Length; i++) {
364            Point p = new Point(points[i].X - 3, points[i].Y - 3);
365            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
366            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
367          }
368        }
369        return newBitmap;
370      }
371      return null;
372    }
373    #endregion
374
375    #region Draw assignment
376    private Bitmap GenerateAssignmentImage() {
377      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
378        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
379
380        for (int i = 0; i < distances.Rows; i++) {
381          for (int j = i + 1; j < distances.Rows; j++) {
382            if (distances[i, j] != distances[j, i]) {
383              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
384              return newBitmap;
385            }
386            if (weights[i, j] != weights[j, i]) {
387              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
388            }
389          }
390        }
391
392        double stress;
393        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
394        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
395        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
396        double maxWeight = double.MinValue;
397        for (int i = 0; i < coordinates.Rows; i++) {
398          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
399          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
400          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
401          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
402
403          for (int j = i + 1; j < coordinates.Rows; j++) {
404            if (weights[i, j] > maxWeight) maxWeight = weights[i, j];
405          }
406        }
407
408        int border = 20;
409        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
410        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
411
412        Point[] points = new Point[coordinates.Rows];
413        for (int i = 0; i < coordinates.Rows; i++)
414          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
415                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
416
417        Random rand = new Random();
418        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
419          graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
420          graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
421
422          for (int i = 0; i < assignment.Length - 1; i++) {
423            for (int j = i + 1; j < assignment.Length; j++) {
424              Point start, end;
425              string caption = String.Empty;
426              double d = distances[i, j];
427              start = points[assignment[i]];
428              end = points[assignment[j]];
429              double w = weights[i, j];
430              if (w > 0) {
431                float width = (float)Math.Ceiling(4.0 * w / maxWeight);
432                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
433                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
434              }
435              if (!String.IsNullOrEmpty(caption)) {
436                double r = rand.NextDouble();
437                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
438                float x = (float)(start.X + (end.X - start.X) * r + 5);
439                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
440                graphics.DrawString(caption, Font, Brushes.Black, x, y);
441              }
442            }
443          }
444
445          for (int i = 0; i < points.Length; i++) {
446            Point p = new Point(points[i].X - 3, points[i].Y - 3);
447            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
448            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
449          }
450        }
451        return newBitmap;
452      }
453      return null;
454    }
455    #endregion
456
457    private void CustomDispose(bool disposing) {
458      DeregisterDistancesEvents();
459      DeregisterWeightsEvents();
460      DeregisterAssignmentEvents();
461      if (bitmap != null) bitmap.Dispose();
462      bitmap = null;
463      if (defaultBitmap != null) {
464        defaultBitmap.Dispose();
465        defaultBitmap = null;
466      }
467    }
468  }
469}
Note: See TracBrowser for help on using the repository browser.