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

Last change on this file since 12806 was 12806, checked in by abeham, 5 years ago

#2431: added options to add results based on targets or budgets

File size: 16.1 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.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Analysis;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
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    public new RunCollection Content {
42      get { return (RunCollection)base.Content; }
43      set { base.Content = value; }
44    }
45
46    private double[] levels;
47
48    private bool suppressUpdates;
49    private readonly IndexedDataTable<double> combinedDataTable;
50    public IndexedDataTable<double> CombinedDataTable {
51      get { return combinedDataTable; }
52    }
53
54    public RunCollectionRLDView() {
55      InitializeComponent();
56      combinedDataTable = new IndexedDataTable<double>("Combined DataTable", "A data table containing the ECDF of each of a number of groups.") {
57        VisualProperties = { YAxisTitle = "Proportion of reached targets" }
58      };
59      viewHost.Content = combinedDataTable;
60      suppressUpdates = false;
61    }
62
63    #region Content events
64    protected override void RegisterContentEvents() {
65      base.RegisterContentEvents();
66      Content.ItemsAdded += Content_ItemsAdded;
67      Content.ItemsRemoved += Content_ItemsRemoved;
68      Content.CollectionReset += Content_CollectionReset;
69      Content.UpdateOfRunsInProgressChanged += Content_UpdateOfRunsInProgressChanged;
70      Content.OptimizerNameChanged += Content_AlgorithmNameChanged;
71    }
72    protected override void DeregisterContentEvents() {
73      Content.ItemsAdded -= Content_ItemsAdded;
74      Content.ItemsRemoved -= Content_ItemsRemoved;
75      Content.CollectionReset -= Content_CollectionReset;
76      Content.UpdateOfRunsInProgressChanged -= Content_UpdateOfRunsInProgressChanged;
77      Content.OptimizerNameChanged -= Content_AlgorithmNameChanged;
78      base.DeregisterContentEvents();
79    }
80
81    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
82      if (suppressUpdates) return;
83      if (InvokeRequired) {
84        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded), sender, e);
85        return;
86      }
87      UpdateGroupComboBox();
88      UpdateDataTableComboBox();
89      foreach (var run in e.Items)
90        RegisterRunEvents(run);
91    }
92    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
93      if (suppressUpdates) return;
94      if (InvokeRequired) {
95        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved), sender, e);
96        return;
97      }
98      UpdateGroupComboBox();
99      UpdateDataTableComboBox();
100      foreach (var run in e.Items)
101        DeregisterRunEvents(run);
102    }
103    private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
104      if (suppressUpdates) return;
105      if (InvokeRequired) {
106        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset), sender, e);
107        return;
108      }
109      UpdateGroupComboBox();
110      UpdateDataTableComboBox();
111      foreach (var run in e.OldItems)
112        DeregisterRunEvents(run);
113    }
114    private void Content_AlgorithmNameChanged(object sender, EventArgs e) {
115      if (InvokeRequired)
116        Invoke(new EventHandler(Content_AlgorithmNameChanged), sender, e);
117      else UpdateCaption();
118    }
119    private void Content_UpdateOfRunsInProgressChanged(object sender, EventArgs e) {
120      if (InvokeRequired) {
121        Invoke(new EventHandler(Content_UpdateOfRunsInProgressChanged), sender, e);
122        return;
123      }
124      suppressUpdates = Content.UpdateOfRunsInProgress;
125      if (!suppressUpdates) {
126        UpdateDataTableComboBox();
127        UpdateGroupComboBox();
128        UpdateRuns();
129      }
130    }
131
132    private void RegisterRunEvents(IRun run) {
133      run.PropertyChanged += run_PropertyChanged;
134    }
135    private void DeregisterRunEvents(IRun run) {
136      run.PropertyChanged -= run_PropertyChanged;
137    }
138    private void run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
139      if (suppressUpdates) return;
140      if (InvokeRequired) {
141        Invoke((Action<object, PropertyChangedEventArgs>)run_PropertyChanged, sender, e);
142      } else {
143        if (e.PropertyName == "Visible")
144          UpdateRuns();
145      }
146    }
147    #endregion
148
149    protected override void OnContentChanged() {
150      base.OnContentChanged();
151      dataTableComboBox.Items.Clear();
152      groupComboBox.Items.Clear();
153      combinedDataTable.Rows.Clear();
154
155      UpdateCaption();
156      if (Content != null) {
157        UpdateGroupComboBox();
158        UpdateDataTableComboBox();
159      }
160    }
161
162    protected override void SetEnabledStateOfControls() {
163      base.SetEnabledStateOfControls();
164      groupComboBox.Enabled = Content != null;
165      dataTableComboBox.Enabled = Content != null;
166      fixedTargetButton.Enabled = Content != null && levels != null && dataTableComboBox.SelectedIndex >= 0;
167    }
168
169    private void UpdateRuns() {
170      if (InvokeRequired) {
171        Invoke((Action)UpdateRuns);
172        return;
173      }
174      SuspendRepaint();
175      try {
176        combinedDataTable.VisualProperties.XAxisLogScale = false;
177        combinedDataTable.Rows.Clear();
178        var table = (string)dataTableComboBox.SelectedItem;
179        if (string.IsNullOrEmpty(table)) return;
180        if (levels == null) {
181          var worst = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).First();
182          var best = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Last();
183          levels = Enumerable.Range(0, 11).Select(x => worst + (x / 10.0) * (best - worst)).ToArray();
184          suppressTargetsEvents = true;
185          targetsTextBox.Text = string.Join(" ; ", levels);
186          suppressTargetsEvents = false;
187        }
188        var selectedGroup = (string)groupComboBox.SelectedItem;
189        if (string.IsNullOrEmpty(selectedGroup)) return;
190        List<Tuple<string, List<IRun>>> groupedRuns;
191        if (selectedGroup == AllRuns)
192          groupedRuns = new List<Tuple<string, List<IRun>>> { Tuple.Create(AllRuns, Content.ToList()) };
193        else groupedRuns = (from r in Content
194                            group r by r.Parameters[selectedGroup].ToString() into g
195                            select Tuple.Create(g.Key, g.ToList())).ToList();
196        var xAxisTitles = new HashSet<string>();
197        foreach (var group in groupedRuns) {
198          var hits = new SortedList<double, int>();
199          foreach (var run in group.Item2) {
200            var resultsTable = (IndexedDataTable<double>)run.Results[table];
201            xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
202            var values = resultsTable.Rows.First().Values;
203            var maximization = values.First().Item2 < values.Last().Item2;
204            var i = 0;
205            var j = 0;
206            var current = values[j];
207            var prev = Tuple.Create(-1.0, double.NaN);
208            while (i < levels.Length) {
209              if ((double.IsNaN(prev.Item2) || prev.Item2 != current.Item2)
210                  && (maximization && current.Item2 >= levels[i]
211                  || !maximization && current.Item2 <= levels[i])) {
212                if (hits.ContainsKey(current.Item1))
213                  hits[current.Item1]++;
214                else hits[current.Item1] = 1;
215                i++;
216              } else {
217                j++;
218                if (j >= values.Count) break;
219                prev = current;
220                current = values[j];
221              }
222            }
223          }
224          var row = new IndexedDataRow<double>(group.Item1) { VisualProperties = { ChartType = DataRowVisualProperties.DataRowChartType.StepLine } };
225          var total = 0.0;
226          foreach (var h in hits) {
227            total += h.Value;
228            row.Values.Add(Tuple.Create(h.Key, total / (group.Item2.Count * levels.Length)));
229          }
230          combinedDataTable.Rows.Add(row);
231        }
232        combinedDataTable.VisualProperties.XAxisTitle = string.Join(" / ", xAxisTitles);
233        combinedDataTable.VisualProperties.XAxisLogScale = logScalingCheckBox.Checked;
234      } finally { ResumeRepaint(true); }
235    }
236
237    private void UpdateGroupComboBox() {
238      string selectedItem = (string)groupComboBox.SelectedItem;
239
240      var groupings = Content.ParameterNames.OrderBy(x => x).ToArray();
241      groupComboBox.Items.Clear();
242      groupComboBox.Items.Add(AllRuns);
243      groupComboBox.Items.AddRange(groupings);
244      if (selectedItem != null && groupComboBox.Items.Contains(selectedItem)) {
245        groupComboBox.SelectedItem = selectedItem;
246      } else if (groupComboBox.Items.Count > 0) {
247        groupComboBox.SelectedItem = groupComboBox.Items[0];
248      }
249    }
250
251    private void UpdateDataTableComboBox() {
252      string selectedItem = (string)dataTableComboBox.SelectedItem;
253
254      dataTableComboBox.Items.Clear();
255      var dataTables = (from run in Content
256                        from result in run.Results
257                        where result.Value is IndexedDataTable<double>
258                        select result.Key).Distinct().ToArray();
259
260      dataTableComboBox.Items.AddRange(dataTables);
261      if (selectedItem != null && dataTableComboBox.Items.Contains(selectedItem)) {
262        dataTableComboBox.SelectedItem = selectedItem;
263      } else if (dataTableComboBox.Items.Count > 0) {
264        dataTableComboBox.SelectedItem = dataTableComboBox.Items[0];
265      }
266    }
267
268    private void UpdateCaption() {
269      Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
270    }
271
272    private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) {
273      UpdateRuns();
274      SetEnabledStateOfControls();
275    }
276    private void dataTableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
277      UpdateRuns();
278      SetEnabledStateOfControls();
279    }
280
281    private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) {
282      combinedDataTable.VisualProperties.XAxisLogScale = logScalingCheckBox.Checked;
283    }
284
285    private bool suppressTargetsEvents;
286    private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
287      if (suppressTargetsEvents) return;
288      var targetStrings = targetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
289      var targetList = new List<double>();
290      foreach (var ts in targetStrings) {
291        double t;
292        if (!double.TryParse(ts, out t)) {
293          errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
294          e.Cancel = true;
295          return;
296        }
297        targetList.Add(t);
298      }
299      if (targetList.Count == 0) {
300        errorProvider.SetError(targetsTextBox, "Give at least one target value!");
301        e.Cancel = true;
302        return;
303      }
304      e.Cancel = false;
305      errorProvider.SetError(targetsTextBox, null);
306      levels = targetList.ToArray();
307      UpdateRuns();
308      SetEnabledStateOfControls();
309    }
310
311    private void generateTargetsButton_Click(object sender, EventArgs e) {
312      decimal max = 1, min = 0, count = 10;
313      if (levels != null) {
314        max = (decimal)Math.Max(levels.First(), levels.Last());
315        min = (decimal)Math.Min(levels.First(), levels.Last());
316        count = levels.Length;
317      } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
318        var table = (string)dataTableComboBox.SelectedItem;
319        var worst = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).First();
320        var best = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Last();
321        max = (decimal)Math.Max(best, worst);
322        min = (decimal)Math.Min(best, worst);
323        count = 10;
324      }
325      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
326        if (dialog.ShowDialog() == DialogResult.OK) {
327          if (dialog.Values.Any()) {
328            var maximization = true;
329            if (Content.Count > 0 && Content.First().Parameters.ContainsKey("Maximization"))
330              maximization = ((BoolValue)Content.First().Parameters["Maximization"]).Value;
331
332            levels = maximization ? dialog.Values.Select(x => (double)x).ToArray()
333                                  : dialog.Values.Reverse().Select(x => (double)x).ToArray();
334            UpdateRuns();
335            SetEnabledStateOfControls();
336          }
337        }
338      }
339    }
340
341    private void fixedTargetButton_Click(object sender, EventArgs e) {
342      var table = (string)dataTableComboBox.SelectedItem;
343      foreach (var run in Content) {
344        var resultsTable = (IndexedDataTable<double>)run.Results[table];
345        var values = resultsTable.Rows.First().Values;
346        var maximization = values.First().Item2 < values.Last().Item2;
347        var i = 0;
348        var j = 0;
349        var current = values[j];
350        var prev = Tuple.Create(-1.0, double.NaN);
351        while (i < levels.Length) {
352          if (prev.Item2 != current.Item2
353              && (maximization && current.Item2 >= levels[i]
354              || !maximization && current.Item2 <= levels[i])) {
355            run.Results[table + ".Target" + levels[i]] = new DoubleValue(current.Item1);
356            i++;
357          } else {
358            j++;
359            if (j >= values.Count) break;
360            prev = current;
361            current = values[j];
362          }
363        }
364      }
365    }
366
367    private void fixedCostButton_Click(object sender, EventArgs e) {
368      var table = (string)dataTableComboBox.SelectedItem;
369      var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
370      if (budgetStrings.Length == 0) {
371        MessageBox.Show("Define a number of budgets.");
372        return;
373      }
374      var budgetList = new List<double>();
375      foreach (var bs in budgetStrings) {
376        double v;
377        if (!double.TryParse(bs, out v)) {
378          MessageBox.Show("Budgets must be a valid number: " + bs);
379          return;
380        }
381        budgetList.Add(v);
382      }
383      budgetList.Sort();
384
385      foreach (var run in Content) {
386        var resultsTable = (IndexedDataTable<double>)run.Results[table];
387        var values = resultsTable.Rows.First().Values;
388        var i = 0;
389        var j = 0;
390        var current = values[j];
391        var prev = Tuple.Create(-1.0, double.NaN);
392        while (i < budgetList.Count) {
393          if (prev.Item2 != current.Item2 && current.Item1 >= budgetList[i]) {
394            run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(double.IsNaN(prev.Item2) || current.Item1 == budgetList[i] ? current.Item2 : prev.Item2);
395            i++;
396          } else {
397            j++;
398            if (j >= values.Count) break;
399            prev = current;
400            current = values[j];
401          }
402        }
403      }
404    }
405  }
406}
Note: See TracBrowser for help on using the repository browser.