Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2431: updated RLD analysis view

  • Added analysis by cost
  • Prepared tab for output of ERT tables
File size: 30.8 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(0x40, 0x6A, 0xB7),
43      Color.FromArgb(0xB1, 0x6D, 0x01),
44      Color.FromArgb(0x4E, 0x8A, 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(0x29, 0x50, 0xCF),
50      Color.FromArgb(0x90, 0xB0, 0x60),
51      Color.FromArgb(0xF5, 0x89, 0x30),
52      Color.FromArgb(0x55, 0x57, 0x53),
53      Color.FromArgb(0xEF, 0x59, 0x59),
54      Color.FromArgb(0xED, 0xD4, 0x30),
55      Color.FromArgb(0x63, 0xC2, 0x16),
56    };
57    private static readonly DataRowVisualProperties.DataRowLineStyle[] lineStyles = new[] {
58      DataRowVisualProperties.DataRowLineStyle.Solid,
59      DataRowVisualProperties.DataRowLineStyle.Dash,
60      DataRowVisualProperties.DataRowLineStyle.DashDot,
61      DataRowVisualProperties.DataRowLineStyle.Dot
62    };
63
64    public new RunCollection Content {
65      get { return (RunCollection)base.Content; }
66      set { base.Content = value; }
67    }
68
69    private double[] targets;
70    private double[] budgets;
71
72    private bool suppressUpdates;
73    private readonly IndexedDataTable<double> byTargetDataTable;
74    public IndexedDataTable<double> ByTargetDataTable {
75      get { return byTargetDataTable; }
76    }
77    private readonly IndexedDataTable<double> byCostDataTable;
78    public IndexedDataTable<double> ByCostDataTable {
79      get { return byCostDataTable; }
80    }
81
82    public RunCollectionRLDView() {
83      InitializeComponent();
84      byTargetDataTable = new IndexedDataTable<double>("ECDF by Target", "A data table containing the ECDF of each of a number of groups.") {
85        VisualProperties = {
86          YAxisTitle = "Proportion of reached targets",
87          YAxisMinimumFixedValue = 0, YAxisMinimumAuto = false,
88          YAxisMaximumFixedValue = 1, YAxisMaximumAuto = false
89        }
90      };
91      byTargetViewHost.Content = byTargetDataTable;
92      byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of each of a number of groups.") {
93        VisualProperties = {
94          YAxisTitle = "Proportion of required budgets",
95          YAxisMinimumFixedValue = 0, YAxisMinimumAuto = false,
96          YAxisMaximumFixedValue = 1, YAxisMaximumAuto = false
97        }
98      };
99      byCostViewHost.Content = byCostDataTable;
100      suppressUpdates = false;
101    }
102
103    #region Content events
104    protected override void RegisterContentEvents() {
105      base.RegisterContentEvents();
106      Content.ItemsAdded += Content_ItemsAdded;
107      Content.ItemsRemoved += Content_ItemsRemoved;
108      Content.CollectionReset += Content_CollectionReset;
109      Content.UpdateOfRunsInProgressChanged += Content_UpdateOfRunsInProgressChanged;
110      Content.OptimizerNameChanged += Content_AlgorithmNameChanged;
111    }
112    protected override void DeregisterContentEvents() {
113      Content.ItemsAdded -= Content_ItemsAdded;
114      Content.ItemsRemoved -= Content_ItemsRemoved;
115      Content.CollectionReset -= Content_CollectionReset;
116      Content.UpdateOfRunsInProgressChanged -= Content_UpdateOfRunsInProgressChanged;
117      Content.OptimizerNameChanged -= Content_AlgorithmNameChanged;
118      base.DeregisterContentEvents();
119    }
120
121    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
122      if (suppressUpdates) return;
123      if (InvokeRequired) {
124        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded), sender, e);
125        return;
126      }
127      UpdateGroupComboBox();
128      UpdateDataTableComboBox();
129      foreach (var run in e.Items)
130        RegisterRunEvents(run);
131    }
132    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
133      if (suppressUpdates) return;
134      if (InvokeRequired) {
135        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved), sender, e);
136        return;
137      }
138      UpdateGroupComboBox();
139      UpdateDataTableComboBox();
140      foreach (var run in e.Items)
141        DeregisterRunEvents(run);
142    }
143    private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
144      if (suppressUpdates) return;
145      if (InvokeRequired) {
146        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset), sender, e);
147        return;
148      }
149      UpdateGroupComboBox();
150      UpdateDataTableComboBox();
151      foreach (var run in e.OldItems)
152        DeregisterRunEvents(run);
153    }
154    private void Content_AlgorithmNameChanged(object sender, EventArgs e) {
155      if (InvokeRequired)
156        Invoke(new EventHandler(Content_AlgorithmNameChanged), sender, e);
157      else UpdateCaption();
158    }
159    private void Content_UpdateOfRunsInProgressChanged(object sender, EventArgs e) {
160      if (InvokeRequired) {
161        Invoke(new EventHandler(Content_UpdateOfRunsInProgressChanged), sender, e);
162        return;
163      }
164      suppressUpdates = Content.UpdateOfRunsInProgress;
165      if (!suppressUpdates) {
166        UpdateDataTableComboBox();
167        UpdateGroupComboBox();
168        UpdateRuns();
169      }
170    }
171
172    private void RegisterRunEvents(IRun run) {
173      run.PropertyChanged += run_PropertyChanged;
174    }
175    private void DeregisterRunEvents(IRun run) {
176      run.PropertyChanged -= run_PropertyChanged;
177    }
178    private void run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
179      if (suppressUpdates) return;
180      if (InvokeRequired) {
181        Invoke((Action<object, PropertyChangedEventArgs>)run_PropertyChanged, sender, e);
182      } else {
183        if (e.PropertyName == "Visible")
184          UpdateRuns();
185      }
186    }
187    #endregion
188
189    protected override void OnContentChanged() {
190      base.OnContentChanged();
191      dataTableComboBox.Items.Clear();
192      groupComboBox.Items.Clear();
193      byTargetDataTable.Rows.Clear();
194
195      UpdateCaption();
196      if (Content != null) {
197        UpdateGroupComboBox();
198        UpdateDataTableComboBox();
199      }
200    }
201
202
203    private void UpdateGroupComboBox() {
204      string selectedItem = (string)groupComboBox.SelectedItem;
205
206      var groupings = Content.ParameterNames.OrderBy(x => x).ToArray();
207      groupComboBox.Items.Clear();
208      groupComboBox.Items.Add(AllRuns);
209      groupComboBox.Items.AddRange(groupings);
210      if (selectedItem != null && groupComboBox.Items.Contains(selectedItem)) {
211        groupComboBox.SelectedItem = selectedItem;
212      } else if (groupComboBox.Items.Count > 0) {
213        groupComboBox.SelectedItem = groupComboBox.Items[0];
214      }
215    }
216
217    private void UpdateDataTableComboBox() {
218      string selectedItem = (string)dataTableComboBox.SelectedItem;
219
220      dataTableComboBox.Items.Clear();
221      var dataTables = (from run in Content
222                        from result in run.Results
223                        where result.Value is IndexedDataTable<double>
224                        select result.Key).Distinct().ToArray();
225
226      dataTableComboBox.Items.AddRange(dataTables);
227      if (selectedItem != null && dataTableComboBox.Items.Contains(selectedItem)) {
228        dataTableComboBox.SelectedItem = selectedItem;
229      } else if (dataTableComboBox.Items.Count > 0) {
230        dataTableComboBox.SelectedItem = dataTableComboBox.Items[0];
231      }
232    }
233
234    protected override void SetEnabledStateOfControls() {
235      base.SetEnabledStateOfControls();
236      groupComboBox.Enabled = Content != null;
237      dataTableComboBox.Enabled = Content != null;
238      addTargetsAsResultButton.Enabled = Content != null && targets != null && dataTableComboBox.SelectedIndex >= 0;
239      addBudgetsAsResultButton.Enabled = Content != null && budgets != null && dataTableComboBox.SelectedIndex >= 0;
240    }
241
242    private void UpdateRuns() {
243      if (InvokeRequired) {
244        Invoke((Action)UpdateRuns);
245        return;
246      }
247      SuspendRepaint();
248      try {
249        UpdateResultsByTarget();
250        UpdateResultsByCost();
251      } finally { ResumeRepaint(true); }
252    }
253
254    #region Performance analysis by (multiple) target(s)
255    private void UpdateResultsByTarget() {
256      // necessary to reset log scale -> empty chart cannot use log scaling
257      byTargetDataTable.VisualProperties.XAxisLogScale = false;
258      byTargetDataTable.Rows.Clear();
259
260      var table = (string)dataTableComboBox.SelectedItem;
261      if (string.IsNullOrEmpty(table)) return;
262
263      var selectedGroup = (string)groupComboBox.SelectedItem;
264      if (string.IsNullOrEmpty(selectedGroup)) return;
265
266      if (targets == null) GenerateDefaultTargets(table);
267
268      List<Tuple<string, List<IRun>>> groupedRuns;
269      if (selectedGroup == AllRuns)
270        groupedRuns = new List<Tuple<string, List<IRun>>> {
271          Tuple.Create(AllRuns, Content.Where(r => r.Results.ContainsKey(table) && r.Visible).ToList())
272        };
273      else groupedRuns = (from r in Content
274                          where r.Results.ContainsKey(table) && r.Visible
275                          group r by r.Parameters[selectedGroup].ToString() into g
276                          select Tuple.Create(g.Key, g.ToList())).ToList();
277
278      var xAxisTitles = new HashSet<string>();
279      var colorCount = 0;
280      var lineStyleCount = 0;
281      var maximization = IsMaximization();
282
283      foreach (var group in groupedRuns) {
284        var hits = new Dictionary<string, SortedList<double, double>>();
285        var maxLength = 0.0;
286
287        foreach (var run in group.Item2) {
288          var resultsTable = (IndexedDataTable<double>)run.Results[table];
289          xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
290
291          if (eachOrAllTargetCheckBox.Checked) {
292            CalculateHitsForEachTarget(hits, resultsTable.Rows.First(), maximization, group.Item2.Count, group.Item1);
293          } else {
294            maxLength = CalculateHitsForAllTargets(hits, resultsTable.Rows.First(), maximization, group.Item2.Count, group.Item1);
295          }
296        }
297
298        foreach (var list in hits) {
299          var row = new IndexedDataRow<double>(list.Key) {
300            VisualProperties = {
301              ChartType = DataRowVisualProperties.DataRowChartType.StepLine,
302              LineWidth = 2,
303              Color = colors[colorCount],
304              LineStyle = lineStyles[lineStyleCount]
305            }
306          };
307
308          var total = 0.0;
309          foreach (var h in list.Value) {
310            total += h.Value;
311            row.Values.Add(Tuple.Create(h.Key, total));
312          }
313
314          if (maxLength > 0 && (row.Values.Count == 0 || row.Values.Last().Item1 < maxLength))
315            row.Values.Add(Tuple.Create(maxLength, total));
316
317          byTargetDataTable.Rows.Add(row);
318        }
319        colorCount = (colorCount + 1) % colors.Length;
320        if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
321      }
322
323      byTargetDataTable.VisualProperties.XAxisTitle = string.Join(" / ", xAxisTitles);
324      byTargetDataTable.VisualProperties.XAxisLogScale = byTargetDataTable.Rows.Count > 0 && targetLogScalingCheckBox.Checked;
325    }
326
327    private void GenerateDefaultTargets(string table) {
328      var worst = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item2).Min()).Min();
329      var best = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item2).Max()).Max();
330      var maximization = IsMaximization();
331      if (!maximization) {
332        var h = worst;
333        worst = best;
334        best = h;
335      }
336
337      if (best == 0 || Math.Abs(best - worst) < Math.Abs(best * 2))
338        targets = Enumerable.Range(0, 11).Select(x => worst + (x / 10.0) * (best - worst)).ToArray();
339      else if (best > 0) targets = Enumerable.Range(0, 11).Select(x => best * (1.0 + (10 - x) / 10.0)).ToArray();
340      else if (best < 0) targets = Enumerable.Range(0, 11).Select(x => best / (1.0 + (10 - x) / 10.0)).ToArray();
341
342      suppressTargetsEvents = true;
343      targetsTextBox.Text = string.Join(" ; ", targets);
344      suppressTargetsEvents = false;
345    }
346
347    private void CalculateHitsForEachTarget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName) {
348      foreach (var l in targets) {
349        var key = groupName + "-" + l;
350        if (!hits.ContainsKey(key)) hits.Add(key, new SortedList<double, double>());
351        foreach (var v in row.Values) {
352          if (maximization && v.Item2 >= l || !maximization && v.Item2 <= l) {
353            if (hits[key].ContainsKey(v.Item1))
354              hits[key][v.Item1] += 1.0 / groupCount;
355            else hits[key][v.Item1] = 1.0 / groupCount;
356            break;
357          }
358        }
359      }
360    }
361
362    private double CalculateHitsForAllTargets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName) {
363      var values = row.Values;
364      if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList<double, double>());
365
366      var i = 0;
367      var j = 0;
368      while (i < targets.Length && j < values.Count) {
369        var current = values[j];
370        if (maximization && current.Item2 >= targets[i]
371          || !maximization && current.Item2 <= targets[i]) {
372          if (!hits[groupName].ContainsKey(current.Item1)) hits[groupName][current.Item1] = 0;
373          hits[groupName][current.Item1] += 1.0 / (groupCount * targets.Length);
374          i++;
375        } else {
376          j++;
377        }
378      }
379      if (j == values.Count) j--;
380      return values[j].Item1;
381    }
382    #endregion
383
384    #region Performance analysis by (multiple) budget(s)
385    private void UpdateResultsByCost() {
386      // necessary to reset log scale -> empty chart cannot use log scaling
387      byCostDataTable.VisualProperties.XAxisLogScale = false;
388      byCostDataTable.Rows.Clear();
389
390      var table = (string)dataTableComboBox.SelectedItem;
391      if (string.IsNullOrEmpty(table)) return;
392
393      var selectedGroup = (string)groupComboBox.SelectedItem;
394      if (string.IsNullOrEmpty(selectedGroup)) return;
395
396      if (budgets == null) GenerateDefaultBudgets(table);
397
398      List<Tuple<string, List<IRun>>> groupedRuns;
399      if (selectedGroup == AllRuns)
400        groupedRuns = new List<Tuple<string, List<IRun>>> {
401          Tuple.Create(AllRuns, Content.Where(r => r.Results.ContainsKey(table) && r.Visible).ToList())
402        };
403      else groupedRuns = (from r in Content
404                          where r.Results.ContainsKey(table) && r.Visible
405                          group r by r.Parameters[selectedGroup].ToString() into g
406                          select Tuple.Create(g.Key, g.ToList())).ToList();
407
408      var colorCount = 0;
409      var lineStyleCount = 0;
410      var maximization = IsMaximization();
411
412      foreach (var group in groupedRuns) {
413        var hits = new Dictionary<string, SortedList<double, double>>();
414
415        foreach (var run in group.Item2) {
416          var resultsTable = (IndexedDataTable<double>)run.Results[table];
417
418          if (eachOrAllBudgetsCheckBox.Checked) {
419            CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), maximization, group.Item2.Count, group.Item1);
420          } else {
421            CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), maximization, group.Item2.Count, group.Item1);
422          }
423        }
424
425        foreach (var list in hits) {
426          var row = new IndexedDataRow<double>(list.Key) {
427            VisualProperties = {
428              ChartType = DataRowVisualProperties.DataRowChartType.StepLine,
429              LineWidth = 2,
430              Color = colors[colorCount],
431              LineStyle = lineStyles[lineStyleCount]
432            }
433          };
434
435          var total = 0.0;
436          foreach (var h in list.Value) {
437            total += h.Value;
438            row.Values.Add(Tuple.Create(h.Key, total));
439          }
440
441          byCostDataTable.Rows.Add(row);
442        }
443        colorCount = (colorCount + 1) % colors.Length;
444        if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
445      }
446
447      byCostDataTable.VisualProperties.XAxisTitle = "Targets";
448      byCostDataTable.VisualProperties.XAxisLogScale = byCostDataTable.Rows.Count > 0 && budgetLogScalingCheckBox.Checked;
449    }
450
451    private void GenerateDefaultBudgets(string table) {
452      var min = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Min()).Min();
453      var max = Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Max()).Max();
454
455      var maxMagnitude = (int)Math.Ceiling(Math.Log10(max));
456      var minMagnitude = (int)Math.Floor(Math.Log10(min));
457      if (maxMagnitude - minMagnitude >= 3) {
458        budgets = new double[maxMagnitude - minMagnitude];
459        for (var i = minMagnitude; i < maxMagnitude; i++) {
460          budgets[i - minMagnitude] = Math.Pow(10, i);
461        }
462      } else {
463        var range = max - min;
464        budgets = Enumerable.Range(0, 6).Select(x => min + (x / 5.0) * range).ToArray();
465      }
466      suppressBudgetsEvents = true;
467      budgetsTextBox.Text = string.Join(" ; ", budgets);
468      suppressBudgetsEvents = false;
469    }
470
471    private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName) {
472      foreach (var b in budgets) {
473        var key = groupName + "-" + b;
474        if (!hits.ContainsKey(key)) hits.Add(key, new SortedList<double, double>());
475        Tuple<double, double> prev = null;
476        foreach (var v in row.Values) {
477          if (v.Item1 >= b) {
478            // the budget may be too low to achieve any target
479            if (prev == null && v.Item1 != b) break;
480            var tgt = (prev == null || v.Item1 == b) ? v.Item2 : prev.Item2;
481            if (hits[key].ContainsKey(tgt))
482              hits[key][tgt] += 1.0 / groupCount;
483            else hits[key][tgt] = 1.0 / groupCount;
484            break;
485          }
486          prev = v;
487        }
488        if (hits[key].Count == 0) hits.Remove(key);
489      }
490    }
491
492    private void CalculateHitsForAllBudgets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName) {
493      var values = row.Values;
494      if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList<double, double>());
495
496      var i = 0;
497      var j = 0;
498      Tuple<double, double> prev = null;
499      while (i < budgets.Length && j < values.Count) {
500        var current = values[j];
501        if (current.Item1 >= budgets[i]) {
502          if (prev != null || current.Item1 == budgets[i]) {
503            var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
504            if (!hits[groupName].ContainsKey(tgt)) hits[groupName][tgt] = 0;
505            hits[groupName][tgt] += 1.0 / (groupCount * budgets.Length);
506          }
507          i++;
508        } else {
509          j++;
510          prev = current;
511        }
512      }
513      var lastTgt = values.Last().Item2;
514      if (i < budgets.Length && !hits[groupName].ContainsKey(lastTgt)) hits[groupName][lastTgt] = 0;
515      while (i < budgets.Length) {
516        hits[groupName][lastTgt] += 1.0 / (groupCount * budgets.Length);
517        i++;
518      }
519    }
520    #endregion
521
522    private void UpdateCaption() {
523      Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
524    }
525
526    private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) {
527      UpdateRuns();
528      SetEnabledStateOfControls();
529    }
530    private void dataTableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
531      if (dataTableComboBox.SelectedIndex >= 0)
532        GenerateDefaultBudgets((string)dataTableComboBox.SelectedItem);
533      UpdateRuns();
534      SetEnabledStateOfControls();
535    }
536
537    private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) {
538      byTargetDataTable.VisualProperties.XAxisLogScale = byTargetDataTable.Rows.Count > 0 && targetLogScalingCheckBox.Checked;
539      byCostDataTable.VisualProperties.XAxisLogScale = byCostDataTable.Rows.Count > 0 && budgetLogScalingCheckBox.Checked;
540    }
541
542    #region Event handlers for target analysis
543    private bool suppressTargetsEvents;
544    private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
545      if (suppressTargetsEvents) return;
546      var targetStrings = targetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
547      var targetList = new List<double>();
548      foreach (var ts in targetStrings) {
549        double t;
550        if (!double.TryParse(ts, out t)) {
551          errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
552          e.Cancel = true;
553          return;
554        }
555        targetList.Add(t);
556      }
557      if (targetList.Count == 0) {
558        errorProvider.SetError(targetsTextBox, "Give at least one target value!");
559        e.Cancel = true;
560        return;
561      }
562      e.Cancel = false;
563      errorProvider.SetError(targetsTextBox, null);
564      targets = targetList.ToArray();
565      UpdateResultsByTarget();
566      SetEnabledStateOfControls();
567    }
568
569    private void eachOrAllTargetCheckBox_CheckedChanged(object sender, EventArgs e) {
570      var each = eachOrAllTargetCheckBox.Checked;
571      eachOrAllTargetCheckBox.Text = each ? "each" : "all";
572      SuspendRepaint();
573      try {
574        UpdateResultsByTarget();
575      } finally { ResumeRepaint(true); }
576    }
577
578    private void generateTargetsButton_Click(object sender, EventArgs e) {
579      var maximization = IsMaximization();
580      decimal max = 1, min = 0, count = 10;
581      if (targets != null) {
582        max = (decimal)targets.Max();
583        min = (decimal)targets.Min();
584        count = targets.Length;
585      } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
586        var table = (string)dataTableComboBox.SelectedItem;
587        max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).Max();
588        min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Min();
589        count = 6;
590      }
591      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
592        if (dialog.ShowDialog() == DialogResult.OK) {
593          if (dialog.Values.Any()) {
594            targets = maximization ? dialog.Values.Select(x => (double)x).ToArray()
595                                  : dialog.Values.Reverse().Select(x => (double)x).ToArray();
596            suppressTargetsEvents = true;
597            targetsTextBox.Text = string.Join(" ; ", targets);
598            suppressTargetsEvents = false;
599
600            UpdateResultsByTarget();
601            SetEnabledStateOfControls();
602          }
603        }
604      }
605    }
606
607    private void addTargetsAsResultButton_Click(object sender, EventArgs e) {
608      var table = (string)dataTableComboBox.SelectedItem;
609      var maximization = IsMaximization();
610      foreach (var run in Content) {
611        if (!run.Results.ContainsKey(table)) continue;
612        var resultsTable = (IndexedDataTable<double>)run.Results[table];
613        var values = resultsTable.Rows.First().Values;
614        var i = 0;
615        var j = 0;
616        while (i < targets.Length && j < values.Count) {
617          var current = values[j];
618          if (maximization && current.Item2 >= targets[i]
619              || !maximization && current.Item2 <= targets[i]) {
620            run.Results[table + ".Target" + targets[i]] = new DoubleValue(current.Item1);
621            i++;
622          } else {
623            j++;
624          }
625        }
626      }
627    }
628    #endregion
629
630    #region Event handlers for cost analysis
631    private bool suppressBudgetsEvents;
632    private void budgetsTextBox_Validating(object sender, CancelEventArgs e) {
633      if (suppressBudgetsEvents) return;
634      var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
635      var budgetList = new List<double>();
636      foreach (var ts in budgetStrings) {
637        double b;
638        if (!double.TryParse(ts, out b)) {
639          errorProvider.SetError(budgetsTextBox, "Not all targets can be parsed: " + ts);
640          e.Cancel = true;
641          return;
642        }
643        budgetList.Add(b);
644      }
645      if (budgetList.Count == 0) {
646        errorProvider.SetError(budgetsTextBox, "Give at least one target value!");
647        e.Cancel = true;
648        return;
649      }
650      e.Cancel = false;
651      errorProvider.SetError(budgetsTextBox, null);
652      budgets = budgetList.ToArray();
653      UpdateResultsByCost();
654      SetEnabledStateOfControls();
655    }
656
657    private void eachOrAllBudgetsCheckBox_CheckedChanged(object sender, EventArgs e) {
658      var each = eachOrAllBudgetsCheckBox.Checked;
659      eachOrAllBudgetsCheckBox.Text = each ? "each" : "all";
660      SuspendRepaint();
661      try {
662        UpdateResultsByCost();
663      } finally { ResumeRepaint(true); }
664    }
665
666    private void generateBudgetsButton_Click(object sender, EventArgs e) {
667      decimal max = 1, min = 0, count = 10;
668      if (budgets != null) {
669        max = (decimal)budgets.Max();
670        min = (decimal)budgets.Min();
671        count = budgets.Length;
672      } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
673        var table = (string)dataTableComboBox.SelectedItem;
674        min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item1)).Min();
675        max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item1)).Max();
676        count = 6;
677      }
678      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
679        if (dialog.ShowDialog() == DialogResult.OK) {
680          if (dialog.Values.Any()) {
681            budgets = dialog.Values.OrderBy(x => x).Select(x => (double)x).ToArray();
682
683            suppressBudgetsEvents = true;
684            budgetsTextBox.Text = string.Join(" ; ", budgets);
685            suppressBudgetsEvents = false;
686
687            UpdateResultsByCost();
688            SetEnabledStateOfControls();
689          }
690        }
691      }
692    }
693
694    private void addBudgetsAsResultButton_Click(object sender, EventArgs e) {
695      var table = (string)dataTableComboBox.SelectedItem;
696      var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
697      if (budgetStrings.Length == 0) {
698        MessageBox.Show("Define a number of budgets.");
699        return;
700      }
701      var budgetList = new List<double>();
702      foreach (var bs in budgetStrings) {
703        double v;
704        if (!double.TryParse(bs, out v)) {
705          MessageBox.Show("Budgets must be a valid number: " + bs);
706          return;
707        }
708        budgetList.Add(v);
709      }
710      budgetList.Sort();
711
712      foreach (var run in Content) {
713        if (!run.Results.ContainsKey(table)) continue;
714        var resultsTable = (IndexedDataTable<double>)run.Results[table];
715        var values = resultsTable.Rows.First().Values;
716        var i = 0;
717        var j = 0;
718        Tuple<double, double> prev = null;
719        while (i < budgetList.Count && j < values.Count) {
720          var current = values[j];
721          if (current.Item1 >= budgetList[i]) {
722            if (prev != null || current.Item1 == budgetList[i]) {
723              var tgt = (prev == null || current.Item1 == budgetList[i]) ? current.Item2 : prev.Item2;
724              run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(tgt);
725            }
726            i++;
727          } else {
728            j++;
729            prev = current;
730          }
731        }
732      }
733    }
734    #endregion
735
736    #region Helpers
737    // Determines if the RunCollection contains maximization or minimization runs
738    private bool IsMaximization() {
739      if (Content == null) return false;
740      if (Content.Count > 0) {
741        foreach (var run in Content.Where(x => x.Parameters.ContainsKey("Maximization")
742                                            && x.Parameters["Maximization"] is BoolValue)) {
743          if (((BoolValue)run.Parameters["Maximization"]).Value) {
744            return true;
745          } else {
746            return false;
747          }
748        }
749        if (dataTableComboBox.SelectedIndex >= 0) {
750          var selectedTable = (string)dataTableComboBox.SelectedItem;
751          foreach (var run in Content.Where(x => x.Results.ContainsKey(selectedTable))) {
752            var table = run.Results[selectedTable] as IndexedDataTable<double>;
753            if (table == null) continue;
754            var firstRowValues = table.Rows.First().Values;
755            if (firstRowValues.Count < 2) continue;
756            return firstRowValues[0].Item2 < firstRowValues[firstRowValues.Count - 1].Item2;
757          }
758        }
759      }
760      // assume minimization by default
761      return false;
762    }
763    #endregion
764  }
765}
Note: See TracBrowser for help on using the repository browser.