Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs @ 12822

Last change on this file since 12822 was 12822, checked in by abeham, 9 years ago

#2431: if multiple targets are plotted, the same color is used for each group

File size: 19.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Analysis;
29using HeuristicLab.Collections;
30using HeuristicLab.Core.Views;
31using HeuristicLab.Data;
32using HeuristicLab.MainForm;
33using HeuristicLab.MainForm.WindowsForms;
34
35namespace HeuristicLab.Optimization.Views {
36  [View("Run-length Distribution View")]
37  [Content(typeof(RunCollection), false)]
38  public partial class RunCollectionRLDView : ItemView {
39    private const string AllRuns = "All Runs";
40
41    private static readonly Color[] colors = new[] {
42      Color.FromArgb(0x20, 0x4A, 0x87),
43      Color.FromArgb(0xC1, 0x7D, 0x11),
44      Color.FromArgb(0x4E, 0x9A, 0x06),
45      Color.FromArgb(0x75, 0x50, 0x7B),
46      Color.FromArgb(0x72, 0x9F, 0xCF),
47      Color.FromArgb(0xA4, 0x00, 0x00),
48      Color.FromArgb(0xAD, 0x7F, 0xA8),
49      Color.FromArgb(0xF5, 0x79, 0x00),
50      Color.FromArgb(0x55, 0x57, 0x53),
51      Color.FromArgb(0xEF, 0x29, 0x29),
52      Color.FromArgb(0xED, 0xD4, 0x00),
53      Color.FromArgb(0x73, 0xD2, 0x16),
54    };
55
56    public new RunCollection Content {
57      get { return (RunCollection)base.Content; }
58      set { base.Content = value; }
59    }
60
61    private double[] levels;
62
63    private bool suppressUpdates;
64    private readonly IndexedDataTable<double> combinedDataTable;
65    public IndexedDataTable<double> CombinedDataTable {
66      get { return combinedDataTable; }
67    }
68
69    public RunCollectionRLDView() {
70      InitializeComponent();
71      combinedDataTable = new IndexedDataTable<double>("Combined DataTable", "A data table containing the ECDF of each of a number of groups.") {
72        VisualProperties = {
73          YAxisTitle = "Proportion of reached targets",
74          YAxisMinimumFixedValue = 0, YAxisMinimumAuto = false,
75          YAxisMaximumFixedValue = 1, YAxisMaximumAuto = false
76        }
77      };
78      viewHost.Content = combinedDataTable;
79      suppressUpdates = false;
80    }
81
82    #region Content events
83    protected override void RegisterContentEvents() {
84      base.RegisterContentEvents();
85      Content.ItemsAdded += Content_ItemsAdded;
86      Content.ItemsRemoved += Content_ItemsRemoved;
87      Content.CollectionReset += Content_CollectionReset;
88      Content.UpdateOfRunsInProgressChanged += Content_UpdateOfRunsInProgressChanged;
89      Content.OptimizerNameChanged += Content_AlgorithmNameChanged;
90    }
91    protected override void DeregisterContentEvents() {
92      Content.ItemsAdded -= Content_ItemsAdded;
93      Content.ItemsRemoved -= Content_ItemsRemoved;
94      Content.CollectionReset -= Content_CollectionReset;
95      Content.UpdateOfRunsInProgressChanged -= Content_UpdateOfRunsInProgressChanged;
96      Content.OptimizerNameChanged -= Content_AlgorithmNameChanged;
97      base.DeregisterContentEvents();
98    }
99
100    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
101      if (suppressUpdates) return;
102      if (InvokeRequired) {
103        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded), sender, e);
104        return;
105      }
106      UpdateGroupComboBox();
107      UpdateDataTableComboBox();
108      foreach (var run in e.Items)
109        RegisterRunEvents(run);
110    }
111    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
112      if (suppressUpdates) return;
113      if (InvokeRequired) {
114        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved), sender, e);
115        return;
116      }
117      UpdateGroupComboBox();
118      UpdateDataTableComboBox();
119      foreach (var run in e.Items)
120        DeregisterRunEvents(run);
121    }
122    private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
123      if (suppressUpdates) return;
124      if (InvokeRequired) {
125        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset), sender, e);
126        return;
127      }
128      UpdateGroupComboBox();
129      UpdateDataTableComboBox();
130      foreach (var run in e.OldItems)
131        DeregisterRunEvents(run);
132    }
133    private void Content_AlgorithmNameChanged(object sender, EventArgs e) {
134      if (InvokeRequired)
135        Invoke(new EventHandler(Content_AlgorithmNameChanged), sender, e);
136      else UpdateCaption();
137    }
138    private void Content_UpdateOfRunsInProgressChanged(object sender, EventArgs e) {
139      if (InvokeRequired) {
140        Invoke(new EventHandler(Content_UpdateOfRunsInProgressChanged), sender, e);
141        return;
142      }
143      suppressUpdates = Content.UpdateOfRunsInProgress;
144      if (!suppressUpdates) {
145        UpdateDataTableComboBox();
146        UpdateGroupComboBox();
147        UpdateRuns();
148      }
149    }
150
151    private void RegisterRunEvents(IRun run) {
152      run.PropertyChanged += run_PropertyChanged;
153    }
154    private void DeregisterRunEvents(IRun run) {
155      run.PropertyChanged -= run_PropertyChanged;
156    }
157    private void run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
158      if (suppressUpdates) return;
159      if (InvokeRequired) {
160        Invoke((Action<object, PropertyChangedEventArgs>)run_PropertyChanged, sender, e);
161      } else {
162        if (e.PropertyName == "Visible")
163          UpdateRuns();
164      }
165    }
166    #endregion
167
168    protected override void OnContentChanged() {
169      base.OnContentChanged();
170      dataTableComboBox.Items.Clear();
171      groupComboBox.Items.Clear();
172      combinedDataTable.Rows.Clear();
173
174      UpdateCaption();
175      if (Content != null) {
176        UpdateGroupComboBox();
177        UpdateDataTableComboBox();
178      }
179    }
180
181    protected override void SetEnabledStateOfControls() {
182      base.SetEnabledStateOfControls();
183      groupComboBox.Enabled = Content != null;
184      dataTableComboBox.Enabled = Content != null;
185      fixedTargetButton.Enabled = Content != null && levels != null && dataTableComboBox.SelectedIndex >= 0;
186    }
187
188    private void UpdateRuns() {
189      if (InvokeRequired) {
190        Invoke((Action)UpdateRuns);
191        return;
192      }
193      SuspendRepaint();
194      try {
195        combinedDataTable.VisualProperties.XAxisLogScale = false;
196        combinedDataTable.Rows.Clear();
197        var table = (string)dataTableComboBox.SelectedItem;
198        if (string.IsNullOrEmpty(table)) return;
199        if (levels == null) {
200          var worstMin = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.First().Item2).Min();
201          var worstMax = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.First().Item2).Max();
202          var bestMin = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Last().Item2).Min();
203          var bestMax = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Last().Item2).Max();
204          double worst, best;
205          if (Math.Abs(bestMax - worstMin) > Math.Abs(bestMin - worstMax)) {
206            worst = worstMin;
207            best = bestMax;
208          } else {
209            worst = worstMax;
210            best = bestMin;
211          }
212          levels = Enumerable.Range(0, 11).Select(x => worst + (x / 10.0) * (best - worst)).ToArray();
213          suppressTargetsEvents = true;
214          targetsTextBox.Text = string.Join(" ; ", levels);
215          suppressTargetsEvents = false;
216        }
217        var selectedGroup = (string)groupComboBox.SelectedItem;
218        if (string.IsNullOrEmpty(selectedGroup)) return;
219        List<Tuple<string, List<IRun>>> groupedRuns;
220        if (selectedGroup == AllRuns)
221          groupedRuns = new List<Tuple<string, List<IRun>>> { Tuple.Create(AllRuns, Content.ToList()) };
222        else groupedRuns = (from r in Content
223                            group r by r.Parameters[selectedGroup].ToString() into g
224                            select Tuple.Create(g.Key, g.ToList())).ToList();
225        var xAxisTitles = new HashSet<string>();
226        var colorCount = 0;
227        var lineStyles = new[] {
228          DataRowVisualProperties.DataRowLineStyle.Solid,
229          DataRowVisualProperties.DataRowLineStyle.Dash,
230          DataRowVisualProperties.DataRowLineStyle.DashDot,
231          DataRowVisualProperties.DataRowLineStyle.Dot
232        };
233        var lineStyleCount = 0;
234        foreach (var group in groupedRuns) {
235          var hits = new Dictionary<string, SortedList<double, double>>();
236          foreach (var run in group.Item2) {
237            if (!run.Results.ContainsKey(table)) continue;
238            var resultsTable = (IndexedDataTable<double>)run.Results[table];
239            xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
240            var values = resultsTable.Rows.First().Values;
241            var maximization = values.First().Item2 < values.Last().Item2;
242            if (allOrEachTargetCheckBox.Checked) {
243              // each
244              foreach (double l in levels) {
245                var key = "-" + l.ToString();
246                if (!hits.ContainsKey(key)) hits.Add(key, new SortedList<double, double>());
247                foreach (var v in values) {
248                  if (maximization && v.Item2 >= l || !maximization && v.Item2 <= l) {
249                    if (hits[key].ContainsKey(v.Item1))
250                      hits[key][v.Item1] += 1.0 / group.Item2.Count;
251                    else hits[key][v.Item1] = 1.0 / group.Item2.Count;
252                    break;
253                  }
254                }
255              }
256            } else {
257              if (!hits.ContainsKey("all")) hits.Add("all", new SortedList<double, double>());
258              // all
259              var i = 0;
260              var j = 0;
261              var current = values[j];
262              var prev = Tuple.Create(-1.0, double.NaN);
263              while (i < levels.Length) {
264                if ((double.IsNaN(prev.Item2) || prev.Item2 != current.Item2)
265                    && (maximization && current.Item2 >= levels[i]
266                        || !maximization && current.Item2 <= levels[i])) {
267                  if (hits["all"].ContainsKey(current.Item1))
268                    hits["all"][current.Item1] += 1.0 / (group.Item2.Count * levels.Length);
269                  else hits["all"][current.Item1] = 1.0 / (group.Item2.Count * levels.Length);
270                  i++;
271                } else {
272                  j++;
273                  if (j >= values.Count) break;
274                  prev = current;
275                  current = values[j];
276                }
277              }
278            }
279          }
280          foreach (var list in hits) {
281            var row = new IndexedDataRow<double>(group.Item1 + (list.Key != "all" ? list.Key : string.Empty)) {
282              VisualProperties = {
283                ChartType = DataRowVisualProperties.DataRowChartType.StepLine,
284                LineWidth = 2,
285                Color = colors[colorCount],
286                LineStyle = lineStyles[lineStyleCount]
287              }
288            };
289            var total = 0.0;
290            foreach (var h in list.Value) {
291              total += h.Value;
292              row.Values.Add(Tuple.Create(h.Key, total));
293            }
294            combinedDataTable.Rows.Add(row);
295          }
296          colorCount = (colorCount + 1) % colors.Length;
297          if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
298        }
299        combinedDataTable.VisualProperties.XAxisTitle = string.Join(" / ", xAxisTitles);
300        combinedDataTable.VisualProperties.XAxisLogScale = combinedDataTable.Rows.Count > 0 && logScalingCheckBox.Checked;
301      } finally { ResumeRepaint(true); }
302    }
303
304    private void UpdateGroupComboBox() {
305      string selectedItem = (string)groupComboBox.SelectedItem;
306
307      var groupings = Content.ParameterNames.OrderBy(x => x).ToArray();
308      groupComboBox.Items.Clear();
309      groupComboBox.Items.Add(AllRuns);
310      groupComboBox.Items.AddRange(groupings);
311      if (selectedItem != null && groupComboBox.Items.Contains(selectedItem)) {
312        groupComboBox.SelectedItem = selectedItem;
313      } else if (groupComboBox.Items.Count > 0) {
314        groupComboBox.SelectedItem = groupComboBox.Items[0];
315      }
316    }
317
318    private void UpdateDataTableComboBox() {
319      string selectedItem = (string)dataTableComboBox.SelectedItem;
320
321      dataTableComboBox.Items.Clear();
322      var dataTables = (from run in Content
323                        from result in run.Results
324                        where result.Value is IndexedDataTable<double>
325                        select result.Key).Distinct().ToArray();
326
327      dataTableComboBox.Items.AddRange(dataTables);
328      if (selectedItem != null && dataTableComboBox.Items.Contains(selectedItem)) {
329        dataTableComboBox.SelectedItem = selectedItem;
330      } else if (dataTableComboBox.Items.Count > 0) {
331        dataTableComboBox.SelectedItem = dataTableComboBox.Items[0];
332      }
333    }
334
335    private void UpdateCaption() {
336      Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
337    }
338
339    private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) {
340      UpdateRuns();
341      SetEnabledStateOfControls();
342    }
343    private void dataTableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
344      UpdateRuns();
345      SetEnabledStateOfControls();
346    }
347
348    private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) {
349      combinedDataTable.VisualProperties.XAxisLogScale = logScalingCheckBox.Checked;
350    }
351
352    private bool suppressTargetsEvents;
353    private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
354      if (suppressTargetsEvents) return;
355      var targetStrings = targetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
356      var targetList = new List<double>();
357      foreach (var ts in targetStrings) {
358        double t;
359        if (!double.TryParse(ts, out t)) {
360          errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
361          e.Cancel = true;
362          return;
363        }
364        targetList.Add(t);
365      }
366      if (targetList.Count == 0) {
367        errorProvider.SetError(targetsTextBox, "Give at least one target value!");
368        e.Cancel = true;
369        return;
370      }
371      e.Cancel = false;
372      errorProvider.SetError(targetsTextBox, null);
373      levels = targetList.ToArray();
374      UpdateRuns();
375      SetEnabledStateOfControls();
376    }
377
378    private void generateTargetsButton_Click(object sender, EventArgs e) {
379      decimal max = 1, min = 0, count = 10;
380      if (levels != null) {
381        max = (decimal)Math.Max(levels.First(), levels.Last());
382        min = (decimal)Math.Min(levels.First(), levels.Last());
383        count = levels.Length;
384      } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
385        var table = (string)dataTableComboBox.SelectedItem;
386        var worst = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).First();
387        var best = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Last();
388        max = (decimal)Math.Max(best, worst);
389        min = (decimal)Math.Min(best, worst);
390        count = 10;
391      }
392      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
393        if (dialog.ShowDialog() == DialogResult.OK) {
394          if (dialog.Values.Any()) {
395            var maximization = true;
396            if (Content.Count > 0 && Content.First().Parameters.ContainsKey("Maximization"))
397              maximization = ((BoolValue)Content.First().Parameters["Maximization"]).Value;
398
399            levels = maximization ? dialog.Values.Select(x => (double)x).ToArray()
400                                  : dialog.Values.Reverse().Select(x => (double)x).ToArray();
401            suppressTargetsEvents = true;
402            targetsTextBox.Text = string.Join(" ; ", levels);
403            suppressTargetsEvents = false;
404
405            UpdateRuns();
406            SetEnabledStateOfControls();
407          }
408        }
409      }
410    }
411
412    private void fixedTargetButton_Click(object sender, EventArgs e) {
413      var table = (string)dataTableComboBox.SelectedItem;
414      foreach (var run in Content) {
415        if (!run.Results.ContainsKey(table)) continue;
416        var resultsTable = (IndexedDataTable<double>)run.Results[table];
417        var values = resultsTable.Rows.First().Values;
418        var maximization = values.First().Item2 < values.Last().Item2;
419        var i = 0;
420        var j = 0;
421        var current = values[j];
422        var prev = Tuple.Create(-1.0, double.NaN);
423        while (i < levels.Length) {
424          if (prev.Item2 != current.Item2
425              && (maximization && current.Item2 >= levels[i]
426              || !maximization && current.Item2 <= levels[i])) {
427            run.Results[table + ".Target" + levels[i]] = new DoubleValue(current.Item1);
428            i++;
429          } else {
430            j++;
431            if (j >= values.Count) break;
432            prev = current;
433            current = values[j];
434          }
435        }
436      }
437    }
438
439    private void fixedCostButton_Click(object sender, EventArgs e) {
440      var table = (string)dataTableComboBox.SelectedItem;
441      var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
442      if (budgetStrings.Length == 0) {
443        MessageBox.Show("Define a number of budgets.");
444        return;
445      }
446      var budgetList = new List<double>();
447      foreach (var bs in budgetStrings) {
448        double v;
449        if (!double.TryParse(bs, out v)) {
450          MessageBox.Show("Budgets must be a valid number: " + bs);
451          return;
452        }
453        budgetList.Add(v);
454      }
455      budgetList.Sort();
456
457      foreach (var run in Content) {
458        if (!run.Results.ContainsKey(table)) continue;
459        var resultsTable = (IndexedDataTable<double>)run.Results[table];
460        var values = resultsTable.Rows.First().Values;
461        var i = 0;
462        var j = 0;
463        var current = values[j];
464        var prev = Tuple.Create(-1.0, double.NaN);
465        while (i < budgetList.Count) {
466          if (prev.Item2 != current.Item2 && current.Item1 >= budgetList[i]) {
467            run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(double.IsNaN(prev.Item2) || current.Item1 == budgetList[i] ? current.Item2 : prev.Item2);
468            i++;
469          } else {
470            j++;
471            if (j >= values.Count) break;
472            prev = current;
473            current = values[j];
474          }
475        }
476      }
477    }
478
479    private void allOrEachTargetCheckBox_CheckedChanged(object sender, EventArgs e) {
480      var each = allOrEachTargetCheckBox.Checked;
481      allOrEachTargetCheckBox.Text = each ? "each" : "all";
482      UpdateRuns();
483    }
484  }
485}
Note: See TracBrowser for help on using the repository browser.