Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1330

  • Moved MDS into Analysis
  • Added test with some simple examples
File size: 18.6 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) defaultBitmap.Dispose();
147      defaultBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
148      WriteCenteredTextToBitmap(ref defaultBitmap, "No visualization available");
149    }
150
151    private void WriteCenteredTextToBitmap(ref Bitmap bitmap, string text) {
152      using (Graphics g = Graphics.FromImage(bitmap)) {
153        g.TextRenderingHint = TextRenderingHint.AntiAlias;
154        g.SmoothingMode = SmoothingMode.AntiAlias;
155
156        SizeF strSize = g.MeasureString(text, Font);
157        g.DrawString(text, Font, Brushes.Black, (float)(pictureBox.Width - strSize.Width) / 2.0f, (float)(pictureBox.Height - strSize.Height) / 2.0f);
158      }
159    }
160
161    private void OnRedraw() {
162      if (InvokeRequired) {
163        Invoke((Action)OnRedraw, null);
164      } else {
165        GenerateImage();
166      }
167    }
168
169    private void GenerateImage() {
170      Bitmap newBitmap = null;
171      stressLabel.Text = "-";
172      if (distancesRadioButton.Checked && Distances != null && Distances.Rows > 0
173        && Distances.Rows == Distances.Columns) {
174        if (Distances.Rows > 30) {
175          newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
176          WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
177        } else newBitmap = GenerateDistanceImage();
178      } else if (weightsRadioButton.Checked && Weights != null && Weights.Rows > 0
179        && Weights.Rows == Weights.Columns) {
180        if (Weights.Rows > 30) {
181          newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
182          WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
183        } else newBitmap = GenerateWeightsImage();
184      } else if (assignmentRadioButton.Checked
185        && Assignment != null && Assignment.Length > 0
186        && Weights != null && Weights.Rows > 0
187        && Distances != null && Distances.Rows > 0
188        && Weights.Rows == Weights.Columns
189        && Distances.Rows == Distances.Columns
190        && Assignment.Length == Weights.Rows
191        && Assignment.Length == Distances.Rows
192        && Assignment.Validate()) {
193        newBitmap = GenerateAssignmentImage();
194      }
195
196      pictureBox.Image = newBitmap != null ? newBitmap : defaultBitmap;
197      if (bitmap != null) bitmap.Dispose();
198      if (newBitmap != null) bitmap = newBitmap;
199      else bitmap = null;
200    }
201
202    #region Draw distances
203    private Bitmap GenerateDistanceImage() {
204      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
205        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
206
207        for (int i = 0; i < distances.Rows; i++) {
208          for (int j = i + 1; j < distances.Rows; j++)
209            if (distances[i, j] != distances[j, i]) {
210              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
211              return newBitmap;
212            }
213        }
214
215        double stress;
216        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
217        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
218        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
219        double maxDistance = double.MinValue;
220        for (int i = 0; i < coordinates.Rows; i++) {
221          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
222          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
223          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
224          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
225
226          for (int j = i + 1; j < coordinates.Rows; j++) {
227            if (distances[i, j] > maxDistance) maxDistance = distances[i, j];
228            if (distances[j, i] > maxDistance) maxDistance = distances[j, i];
229          }
230        }
231
232        int border = 20;
233        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
234        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
235
236        Point[] points = new Point[coordinates.Rows];
237        for (int i = 0; i < coordinates.Rows; i++)
238          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
239                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
240
241        Random rand = new Random();
242        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
243          graphics.SmoothingMode = SmoothingMode.AntiAlias;
244          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
245          graphics.DrawString("Showing locations spaced out according to their distances", Font, Brushes.Black, 5, 2);
246
247          for (int i = 0; i < coordinates.Rows - 1; i++) {
248            for (int j = i + 1; j < coordinates.Rows; j++) {
249              Point start = points[i], end = points[j];
250              string caption = String.Empty;
251              double d = Math.Max(distances[i, j], distances[j, i]);
252              float width = (float)Math.Ceiling(5.0 * d / maxDistance);
253              if (d > 0) {
254                graphics.DrawLine(new Pen(Color.IndianRed, width), start, end);
255                if (distances[i, j] != distances[j, i])
256                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat)
257                    + " / " + distances[j, i].ToString(CultureInfo.InvariantCulture.NumberFormat);
258                else
259                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat);
260              }
261              if (!String.IsNullOrEmpty(caption)) {
262                double r = rand.NextDouble();
263                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
264                float x = (float)(start.X + (end.X - start.X) * r + 5);
265                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
266                graphics.DrawString(caption, Font, Brushes.Black, x, y);
267              }
268            }
269          }
270
271          for (int i = 0; i < points.Length; i++) {
272            Point p = new Point(points[i].X - 3, points[i].Y - 3);
273            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
274            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
275          }
276        }
277        return newBitmap;
278      }
279      return null;
280    }
281    #endregion
282
283    #region Draw weights
284    private Bitmap GenerateWeightsImage() {
285      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
286        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
287
288        double maxWeight = double.MinValue;
289        for (int i = 0; i < weights.Rows; i++)
290          for (int j = i + 1; j < weights.Rows; j++) {
291            if (weights[i, j] > maxWeight)
292              maxWeight = weights[i, j] + weights[j, i];
293
294            if (weights[i, j] != weights[j, i]) {
295              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
296              return newBitmap;
297            }
298          }
299
300        DoubleMatrix distances = new DoubleMatrix(weights.Rows, weights.Columns);
301        for (int i = 0; i < distances.Rows; i++)
302          for (int j = 0; j < distances.Columns; j++) {
303            distances[i, j] = maxWeight + 1 - weights[i, j];
304          }
305
306        double stress;
307        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
308        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
309        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
310        for (int i = 0; i < coordinates.Rows; i++) {
311          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
312          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
313          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
314          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
315        }
316
317        int border = 20;
318        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
319        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
320
321        Point[] points = new Point[coordinates.Rows];
322        for (int i = 0; i < coordinates.Rows; i++)
323          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
324                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
325
326        Random rand = new Random();
327        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
328          graphics.SmoothingMode = SmoothingMode.AntiAlias;
329          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
330          graphics.DrawString("Showing facilities spaced out according to their weights", Font, Brushes.Black, 5, 2);
331
332          for (int i = 0; i < coordinates.Rows - 1; i++) {
333            for (int j = i + 1; j < coordinates.Rows; j++) {
334              Point start = points[i], end = points[j];
335              string caption = String.Empty;
336              double d = Math.Max(distances[i, j], distances[j, i]);
337              double w = weights[i, j];
338              if (w > 0) {
339                float width = (float)Math.Ceiling(3.0 * w / maxWeight);
340                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
341                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
342              }
343              if (!String.IsNullOrEmpty(caption)) {
344                double r = rand.NextDouble();
345                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
346                float x = (float)(start.X + (end.X - start.X) * r + 5);
347                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
348                graphics.DrawString(caption, Font, Brushes.Black, x, y);
349              }
350            }
351          }
352          for (int i = 0; i < points.Length; i++) {
353            Point p = new Point(points[i].X - 3, points[i].Y - 3);
354            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
355            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
356          }
357        }
358        return newBitmap;
359      }
360      return null;
361    }
362    #endregion
363
364    #region Draw assignment
365    private Bitmap GenerateAssignmentImage() {
366      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
367        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
368
369        for (int i = 0; i < distances.Rows; i++) {
370          for (int j = i + 1; j < distances.Rows; j++) {
371            if (distances[i, j] != distances[j, i]) {
372              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
373              return newBitmap;
374            }
375            if (weights[i, j] != weights[j, i]) {
376              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
377            }
378          }
379        }
380
381        double stress;
382        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
383        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
384        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
385        double maxWeight = double.MinValue;
386        for (int i = 0; i < coordinates.Rows; i++) {
387          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
388          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
389          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
390          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
391
392          for (int j = i + 1; j < coordinates.Rows; j++) {
393            if (weights[i, j] > maxWeight) maxWeight = weights[i, j];
394          }
395        }
396
397        int border = 20;
398        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
399        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
400
401        Point[] points = new Point[coordinates.Rows];
402        for (int i = 0; i < coordinates.Rows; i++)
403          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
404                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
405
406        Random rand = new Random();
407        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
408          graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
409          graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
410
411          for (int i = 0; i < assignment.Length - 1; i++) {
412            for (int j = i + 1; j < assignment.Length; j++) {
413              Point start, end;
414              string caption = String.Empty;
415              double d = distances[i, j];
416              start = points[assignment[i]];
417              end = points[assignment[j]];
418              double w = weights[i, j];
419              if (w > 0) {
420                float width = (float)Math.Ceiling(4.0 * w / maxWeight);
421                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
422                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
423              }
424              if (!String.IsNullOrEmpty(caption)) {
425                double r = rand.NextDouble();
426                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
427                float x = (float)(start.X + (end.X - start.X) * r + 5);
428                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
429                graphics.DrawString(caption, Font, Brushes.Black, x, y);
430              }
431            }
432          }
433
434          for (int i = 0; i < points.Length; i++) {
435            Point p = new Point(points[i].X - 3, points[i].Y - 3);
436            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
437            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
438          }
439        }
440        return newBitmap;
441      }
442      return null;
443    }
444    #endregion
445
446    private void CustomDispose(bool disposing) {
447      DeregisterDistancesEvents();
448      DeregisterWeightsEvents();
449      DeregisterAssignmentEvents();
450      if (bitmap != null) bitmap.Dispose();
451      bitmap = null;
452      defaultBitmap.Dispose();
453      defaultBitmap = null;
454    }
455  }
456}
Note: See TracBrowser for help on using the repository browser.