Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimizer/3.3/CreateExperimentDialog.cs @ 12293

Last change on this file since 12293 was 12293, checked in by pfleck, 9 years ago

#2301 Use decimal instead of double for the DefineArithmeticProgressionDialog and in the CreateExperimentDialog.
Note, when using decimal only during the generate process but not during some calculations (e.g. determining meaningful step sizes), numeric inaccuracies occur.
Therefore some calculations now uses decimal instead of double values.

File size: 37.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.Globalization;
26using System.Linq;
27using System.Text;
28using System.Threading;
29using System.Windows.Forms;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.MainForm.WindowsForms;
33using HeuristicLab.Optimization;
34using HeuristicLab.Parameters;
35using HeuristicLab.Problems.Instances;
36
37namespace HeuristicLab.Optimizer {
38  public partial class CreateExperimentDialog : Form {
39    private enum DialogMode { Normal = 1, DiscoveringInstances = 2, CreatingExperiment = 3, PreparingExperiment = 4 };
40
41    private IOptimizer optimizer;
42    public IOptimizer Optimizer {
43      get { return optimizer; }
44      set {
45        optimizer = value;
46        Experiment = null;
47        okButton.Enabled = optimizer != null;
48        SetTabControlVisibility();
49        FillInstanceTreeViewAsync();
50        FillParametersListView();
51      }
52    }
53
54    public Experiment Experiment { get; private set; }
55
56    private bool createBatchRun;
57    private int repetitions;
58    private Dictionary<IProblemInstanceProvider, HashSet<IDataDescriptor>> instances;
59    private Dictionary<IValueParameter, IntArray> intParameters;
60    private Dictionary<IValueParameter, DoubleArray> doubleParameters;
61    private HashSet<IValueParameter> boolParameters;
62    private Dictionary<IValueParameter, HashSet<IItem>> multipleChoiceParameters;
63    private IItem optionalNullChoice = new BoolValue(); // any item will do
64
65    private StringBuilder failedInstances;
66    private EventWaitHandle backgroundWorkerWaitHandle = new ManualResetEvent(false);
67    private bool suppressTreeViewEventHandling, suppressCheckAllNoneEventHandling;
68
69    public CreateExperimentDialog() : this(null) { }
70    public CreateExperimentDialog(IOptimizer optimizer) {
71      InitializeComponent();
72      instanceDiscoveryProgressLabel.BackColor = instancesTabPage.BackColor;
73      createBatchRun = createBatchRunCheckBox.Checked;
74      repetitions = (int)repetitionsNumericUpDown.Value;
75      // do not set the Optimizer property here, because we want to delay instance discovery to the time when the form loads
76      this.optimizer = optimizer;
77      Experiment = null;
78      okButton.Enabled = optimizer != null;
79
80      instances = new Dictionary<IProblemInstanceProvider, HashSet<IDataDescriptor>>();
81      intParameters = new Dictionary<IValueParameter, IntArray>();
82      doubleParameters = new Dictionary<IValueParameter, DoubleArray>();
83      boolParameters = new HashSet<IValueParameter>();
84      multipleChoiceParameters = new Dictionary<IValueParameter, HashSet<IItem>>();
85    }
86
87    #region Event handlers
88    private void CreateExperimentDialog_Load(object sender, EventArgs e) {
89      SetTabControlVisibility();
90      FillInstanceTreeViewAsync();
91      FillParametersListView();
92    }
93
94    private void CreateExperimentDialog_FormClosing(object sender, FormClosingEventArgs e) {
95      if (experimentCreationBackgroundWorker.IsBusy) {
96        if (DialogResult != System.Windows.Forms.DialogResult.OK) {
97          if (experimentCreationBackgroundWorker.IsBusy) experimentCreationBackgroundWorker.CancelAsync();
98          if (instanceDiscoveryBackgroundWorker.IsBusy) instanceDiscoveryBackgroundWorker.CancelAsync();
99        }
100        e.Cancel = true;
101      }
102    }
103
104    private void okButton_Click(object sender, EventArgs e) {
105      SetMode(DialogMode.CreatingExperiment);
106      experimentCreationBackgroundWorker.RunWorkerAsync();
107      backgroundWorkerWaitHandle.WaitOne(); // make sure the background worker has started before exiting
108    }
109
110    #region Parameters variation
111    private void parametersListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
112      var parameter = (IValueParameter)e.Item.Tag;
113      var isConstrainedValueParameter = typeof(OptionalConstrainedValueParameter<>).Equals(parameter.GetType().GetGenericTypeDefinition())
114        || typeof(ConstrainedValueParameter<>).Equals(parameter.GetType().GetGenericTypeDefinition());
115
116      if (!isConstrainedValueParameter && parameter.Value == null) {
117        if (e.Item.Checked) e.Item.Checked = false;
118        return;
119      }
120
121      if (isConstrainedValueParameter) {
122        if (e.Item.Checked) multipleChoiceParameters.Add(parameter, new HashSet<IItem>());
123        else multipleChoiceParameters.Remove(parameter);
124      } else {
125
126        var intValue = parameter.Value as ValueTypeValue<int>;
127        if (intValue != null) {
128          if (e.Item.Checked) {
129            IntArray initialValues;
130            if (intValue.Value == int.MinValue)
131              initialValues = new IntArray(new int[] { -100, -50, 5 });
132            else if (intValue.Value == int.MaxValue)
133              initialValues = new IntArray(new int[] { 5, 50, 100 });
134            else if (intValue.Value == 0)
135              initialValues = new IntArray(new int[] { 0, 1, 2 });
136            else if (Math.Abs(intValue.Value) < 10)
137              initialValues = new IntArray(new int[] { intValue.Value - 1, intValue.Value, intValue.Value + 1 });
138            else initialValues = new IntArray(new int[] { intValue.Value / 2, intValue.Value, intValue.Value * 2 });
139            intParameters.Add(parameter, initialValues);
140            intParameters[parameter].Reset += new EventHandler(ValuesArray_Reset);
141          } else intParameters.Remove(parameter);
142        }
143
144        var doubleValue = parameter.Value as ValueTypeValue<double>;
145        if (doubleValue != null) {
146          if (e.Item.Checked) {
147            DoubleArray initialValues;
148            if (doubleValue.Value == double.MinValue)
149              initialValues = new DoubleArray(new double[] { -1, -0.5, 0 });
150            else if (doubleValue.Value == double.MaxValue)
151              initialValues = new DoubleArray(new double[] { 0, 0.5, 1 });
152            else if (doubleValue.Value == 0.0)
153              initialValues = new DoubleArray(new double[] { 0, 0.1, 0.2 });
154            else if (Math.Abs(doubleValue.Value) <= 1.0) {
155              if (doubleValue.Value > 0.9 || (doubleValue.Value < 0.0 && doubleValue.Value > -0.1))
156                initialValues = new DoubleArray(new double[] { doubleValue.Value - 0.2, doubleValue.Value - 0.1, doubleValue.Value });
157              else if (doubleValue.Value < -0.9 || (doubleValue.Value > 0 && doubleValue.Value < 0.1))
158                initialValues = new DoubleArray(new double[] { doubleValue.Value, doubleValue.Value + 0.1, doubleValue.Value + 0.2 });
159              else initialValues = new DoubleArray(new double[] { doubleValue.Value - 0.1, doubleValue.Value, doubleValue.Value + 0.1 });
160            } else initialValues = new DoubleArray(new double[] { doubleValue.Value / 2.0, doubleValue.Value, doubleValue.Value * 2.0 });
161            doubleParameters.Add(parameter, initialValues);
162            doubleParameters[parameter].Reset += new EventHandler(ValuesArray_Reset);
163          } else doubleParameters.Remove(parameter);
164        }
165
166        var boolValue = parameter.Value as ValueTypeValue<bool>;
167        if (boolValue != null) {
168          if (e.Item.Checked) boolParameters.Add(parameter);
169          else boolParameters.Remove(parameter);
170        }
171      }
172
173      UpdateVariationsLabel();
174      if (e.Item.Selected) UpdateDetailsView(parameter);
175      else e.Item.Selected = true;
176    }
177
178    private void parametersListView_SelectedIndexChanged(object sender, EventArgs e) {
179      if (parametersListView.SelectedItems.Count == 0) {
180        ClearDetailsView();
181      } else {
182        var parameter = parametersListView.SelectedItems[0].Tag as IValueParameter;
183        UpdateDetailsView(parameter);
184      }
185    }
186
187    private void UpdateDetailsView(IValueParameter parameter) {
188      ClearDetailsView();
189
190      var isOptionalConstrainedValueParameter = typeof(OptionalConstrainedValueParameter<>).IsAssignableFrom(parameter.GetType().GetGenericTypeDefinition());
191      var isConstrainedValueParameter =
192        isOptionalConstrainedValueParameter
193        || typeof(ConstrainedValueParameter<>).Equals(parameter.GetType().GetGenericTypeDefinition());
194
195      if (isConstrainedValueParameter) {
196        detailsTypeLabel.Text = "Choices:";
197        choicesListView.Tag = parameter;
198
199        if (isOptionalConstrainedValueParameter) {
200          choicesListView.Items.Add(new ListViewItem("-") {
201            Tag = optionalNullChoice,
202            Checked = multipleChoiceParameters.ContainsKey(parameter)
203            && multipleChoiceParameters[parameter].Contains(optionalNullChoice)
204          });
205        }
206        dynamic constrainedValuedParameter = parameter;
207        dynamic validValues = constrainedValuedParameter.ValidValues;
208        foreach (var choice in validValues) {
209          choicesListView.Items.Add(new ListViewItem(choice.ToString()) {
210            Tag = choice,
211            Checked = multipleChoiceParameters.ContainsKey(parameter)
212            && multipleChoiceParameters[parameter].Contains(choice)
213          });
214        }
215        choicesListView.Enabled = multipleChoiceParameters.ContainsKey(parameter);
216        detailsTypeLabel.Visible = true;
217        choicesListView.Visible = true;
218        return;
219      }
220
221      if (parameter.Value is ValueTypeValue<bool>) {
222        detailsTypeLabel.Text = "Boolean parameter: True / False";
223        detailsTypeLabel.Visible = true;
224      }
225
226      var intValue = parameter.Value as ValueTypeValue<int>;
227      if (intValue != null) {
228        if (intParameters.ContainsKey(parameter))
229          stringConvertibleArrayView.Content = intParameters[parameter];
230        stringConvertibleArrayView.Visible = true;
231        stringConvertibleArrayView.ReadOnly = !intParameters.ContainsKey(parameter);
232        generateButton.Tag = parameter;
233        generateButton.Enabled = intParameters.ContainsKey(parameter);
234        generateButton.Visible = true;
235        return;
236      }
237
238      var doubleValue = parameter.Value as ValueTypeValue<double>;
239      if (doubleValue != null) {
240        if (doubleParameters.ContainsKey(parameter))
241          stringConvertibleArrayView.Content = doubleParameters[parameter];
242        stringConvertibleArrayView.Visible = true;
243        stringConvertibleArrayView.ReadOnly = !doubleParameters.ContainsKey(parameter);
244        generateButton.Tag = parameter;
245        generateButton.Enabled = doubleParameters.ContainsKey(parameter);
246        generateButton.Visible = true;
247        return;
248      }
249    }
250
251    #region Detail controls
252    private void choiceListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
253      var parameter = (IValueParameter)choicesListView.Tag;
254      if (multipleChoiceParameters.ContainsKey(parameter)) {
255        if (e.Item.Checked) {
256          multipleChoiceParameters[parameter].Add((IItem)e.Item.Tag);
257        } else multipleChoiceParameters[parameter].Remove((IItem)e.Item.Tag);
258
259        UpdateVariationsLabel();
260      }
261    }
262
263    private void generateButton_Click(object sender, EventArgs e) {
264      var parameter = (IValueParameter)generateButton.Tag;
265      bool integerOnly = intParameters.ContainsKey(parameter);
266      decimal min = 0, max = 1, step = 1;
267      #region Try to calculate some meaningful values
268      if (integerOnly) {
269        int len = intParameters[parameter].Length;
270        if (len > 0) {
271          min = intParameters[parameter].Min();
272          max = intParameters[parameter].Max();
273          step = len >= 2 ? Math.Abs((intParameters[parameter][len - 1] - intParameters[parameter][len - 2])) : 1;
274        }
275      } else {
276        int len = doubleParameters[parameter].Length;
277        if (len > 0) {
278          min = (decimal)doubleParameters[parameter].Min();
279          max = (decimal)doubleParameters[parameter].Max();
280          step = len >= 2 ? Math.Abs(((decimal)doubleParameters[parameter][len - 1] - (decimal)doubleParameters[parameter][len - 2])) : 1m;
281        }
282      }
283      #endregion
284      using (var dialog = new DefineArithmeticProgressionDialog(integerOnly, min, max, step)) {
285        if (dialog.ShowDialog(this) == DialogResult.OK) {
286          var values = dialog.Values;
287          if (integerOnly) {
288            intParameters[parameter].Reset -= new EventHandler(ValuesArray_Reset);
289            intParameters[parameter] = new IntArray(values.Select(x => (int)x).ToArray());
290            intParameters[parameter].Reset += new EventHandler(ValuesArray_Reset);
291            stringConvertibleArrayView.Content = intParameters[parameter];
292          } else {
293            doubleParameters[parameter].Reset -= new EventHandler(ValuesArray_Reset);
294            doubleParameters[parameter] = new DoubleArray(values.Select(x => (double)x).ToArray());
295            doubleParameters[parameter].Reset += new EventHandler(ValuesArray_Reset);
296            stringConvertibleArrayView.Content = doubleParameters[parameter];
297          }
298          UpdateVariationsLabel();
299        }
300      }
301    }
302
303    private void ValuesArray_Reset(object sender, EventArgs e) {
304      UpdateVariationsLabel();
305    }
306    #endregion
307    #endregion
308
309    #region Instances
310    private void instancesTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
311      if (!suppressTreeViewEventHandling) {
312        if (e.Node.Nodes.Count > 0) { // provider node was (un)checked
313          SyncProviderNode(e.Node);
314        } else { // descriptor node was (un)checked
315          SyncInstanceNode(e.Node);
316        }
317
318        suppressCheckAllNoneEventHandling = true;
319        try {
320          var treeViewNodes = instancesTreeView.Nodes.OfType<TreeNode>().SelectMany(x => x.Nodes.OfType<TreeNode>());
321          selectAllCheckBox.Checked = treeViewNodes.Count() == instances.SelectMany(x => x.Value).Count();
322          selectNoneCheckBox.Checked = !treeViewNodes.Any(x => x.Checked);
323        } finally { suppressCheckAllNoneEventHandling = false; }
324        UpdateVariationsLabel();
325      }
326    }
327
328    private void SyncProviderNode(TreeNode node) {
329      suppressTreeViewEventHandling = true;
330      try {
331        foreach (TreeNode n in node.Nodes) {
332          if (n.Checked != node.Checked) {
333            n.Checked = node.Checked;
334            SyncInstanceNode(n, false);
335          }
336        }
337      } finally { suppressTreeViewEventHandling = false; }
338    }
339
340    private void SyncInstanceNode(TreeNode node, bool providerCheck = true) {
341      var provider = (IProblemInstanceProvider)node.Parent.Tag;
342      var descriptor = (IDataDescriptor)node.Tag;
343      if (node.Checked) {
344        if (!instances.ContainsKey(provider))
345          instances.Add(provider, new HashSet<IDataDescriptor>());
346        instances[provider].Add(descriptor);
347      } else {
348        if (instances.ContainsKey(provider)) {
349          instances[provider].Remove(descriptor);
350          if (instances[provider].Count == 0)
351            instances.Remove(provider);
352        }
353      }
354      if (providerCheck) {
355        bool allChecked = node.Parent.Nodes.OfType<TreeNode>().All(x => x.Checked);
356        suppressTreeViewEventHandling = true;
357        try {
358          node.Parent.Checked = allChecked;
359        } finally { suppressTreeViewEventHandling = false; }
360      }
361    }
362
363    private void selectAllCheckBox_CheckedChanged(object sender, EventArgs e) {
364      if (!suppressCheckAllNoneEventHandling) {
365        if (selectAllCheckBox.Checked) {
366          suppressCheckAllNoneEventHandling = true;
367          try { selectNoneCheckBox.Checked = false; } finally { suppressCheckAllNoneEventHandling = false; }
368          try {
369            suppressTreeViewEventHandling = true;
370            foreach (TreeNode node in instancesTreeView.Nodes) {
371              if (!node.Checked) {
372                node.Checked = true;
373                SyncProviderNode(node);
374              }
375            }
376          } finally { suppressTreeViewEventHandling = false; }
377        }
378        UpdateVariationsLabel();
379      }
380    }
381
382    private void selectNoneCheckBox_CheckedChanged(object sender, EventArgs e) {
383      if (!suppressCheckAllNoneEventHandling) {
384        if (selectNoneCheckBox.Checked) {
385          suppressCheckAllNoneEventHandling = true;
386          try { selectAllCheckBox.Checked = false; } finally { suppressCheckAllNoneEventHandling = false; }
387          try {
388            suppressTreeViewEventHandling = true;
389            foreach (TreeNode node in instancesTreeView.Nodes) {
390              if (node.Checked) {
391                node.Checked = false;
392                SyncProviderNode(node);
393              }
394            }
395          } finally { suppressTreeViewEventHandling = false; }
396        }
397        UpdateVariationsLabel();
398      }
399    }
400    #endregion
401
402    private void createBatchRunCheckBox_CheckedChanged(object sender, EventArgs e) {
403      repetitionsNumericUpDown.Enabled = createBatchRunCheckBox.Checked;
404      createBatchRun = createBatchRunCheckBox.Checked;
405    }
406
407    private void repetitionsNumericUpDown_Validated(object sender, EventArgs e) {
408      if (repetitionsNumericUpDown.Text == string.Empty)
409        repetitionsNumericUpDown.Text = repetitionsNumericUpDown.Value.ToString();
410      repetitions = (int)repetitionsNumericUpDown.Value;
411    }
412
413    private void experimentsLabel_TextChanged(object sender, EventArgs e) {
414      long number;
415      if (long.TryParse(variationsLabel.Text, NumberStyles.AllowThousands, CultureInfo.CurrentCulture.NumberFormat, out number)) {
416        if (number > 1000) warningProvider.SetError(variationsLabel, "Consider reducing the number of variations!");
417        else warningProvider.SetError(variationsLabel, null);
418      }
419    }
420    #endregion
421
422    #region Helpers
423    private void SetTabControlVisibility() {
424      bool isAlgorithm = optimizer != null && optimizer is IAlgorithm;
425      bool instancesAvailable = isAlgorithm
426        && ((IAlgorithm)optimizer).Problem != null
427        && ProblemInstanceManager.GetProviders(((IAlgorithm)optimizer).Problem).Any();
428      if (instancesAvailable && tabControl.TabCount == 1)
429        tabControl.TabPages.Add(instancesTabPage);
430      else if (!instancesAvailable && tabControl.TabCount == 2)
431        tabControl.TabPages.Remove(instancesTabPage);
432      tabControl.Visible = isAlgorithm;
433      if (isAlgorithm) {
434        variationsLabel.Visible = true;
435        experimentsToCreateDescriptionLabel.Visible = true;
436        Height = 450;
437      } else {
438        variationsLabel.Visible = false;
439        experimentsToCreateDescriptionLabel.Visible = false;
440        Height = 130;
441      }
442    }
443
444    private void FillParametersListView() {
445      parametersListView.Items.Clear();
446      intParameters.Clear();
447      doubleParameters.Clear();
448      boolParameters.Clear();
449      multipleChoiceParameters.Clear();
450
451      if (Optimizer is IAlgorithm) {
452        var parameters = ((IAlgorithm)optimizer).Parameters;
453        foreach (var param in parameters) {
454          var valueParam = param as IValueParameter;
455          if (valueParam != null && (valueParam.Value is ValueTypeValue<bool>
456              || valueParam.Value is ValueTypeValue<int>
457              || valueParam.Value is ValueTypeValue<double>)
458            || typeof(OptionalConstrainedValueParameter<>).IsAssignableFrom(param.GetType().GetGenericTypeDefinition())
459            || typeof(ConstrainedValueParameter<>).IsAssignableFrom(param.GetType().GetGenericTypeDefinition()))
460            parametersListView.Items.Add(new ListViewItem(param.Name) { Tag = param });
461        }
462      }
463    }
464
465    private void FillInstanceTreeViewAsync() {
466      instances.Clear();
467      instancesTreeView.Nodes.Clear();
468
469      if (Optimizer is IAlgorithm && ((IAlgorithm)Optimizer).Problem != null) {
470        SetMode(DialogMode.DiscoveringInstances);
471        instanceDiscoveryBackgroundWorker.RunWorkerAsync();
472      }
473    }
474
475    private void AddOptimizer(IOptimizer optimizer, Experiment experiment) {
476      if (createBatchRun) {
477        var batchRun = new BatchRun(repetitions.ToString() + "x " + optimizer.Name) {
478          Repetitions = repetitions,
479          Optimizer = optimizer
480        };
481        experiment.Optimizers.Add(batchRun);
482      } else {
483        experiment.Optimizers.Add(optimizer);
484      }
485    }
486
487    private int GetNumberOfVariations() {
488      int instancesCount = 1;
489      if (instances.Values.Any())
490        instancesCount = Math.Max(instances.Values.SelectMany(x => x).Count(), 1);
491
492      int intParameterVariations = 1;
493      foreach (var intParam in intParameters.Values) {
494        intParameterVariations *= Math.Max(intParam.Length, 1);
495      }
496      int doubleParameterVariations = 1;
497      foreach (var doubleParam in doubleParameters.Values) {
498        doubleParameterVariations *= Math.Max(doubleParam.Length, 1);
499      }
500      int boolParameterVariations = 1;
501      foreach (var boolParam in boolParameters) {
502        boolParameterVariations *= 2;
503      }
504      int choiceParameterVariations = 1;
505      foreach (var choiceParam in multipleChoiceParameters.Values) {
506        choiceParameterVariations *= Math.Max(choiceParam.Count, 1);
507      }
508
509      return (instancesCount * intParameterVariations * doubleParameterVariations * boolParameterVariations * choiceParameterVariations);
510    }
511
512    private void SetMode(DialogMode mode) {
513      if (InvokeRequired) Invoke((Action<DialogMode>)SetMode, mode);
514      else {
515        createBatchRunCheckBox.Enabled = mode == DialogMode.Normal;
516        repetitionsNumericUpDown.Enabled = mode == DialogMode.Normal;
517        parametersSplitContainer.Enabled = mode == DialogMode.Normal || mode == DialogMode.DiscoveringInstances;
518        selectAllCheckBox.Enabled = mode == DialogMode.Normal;
519        selectNoneCheckBox.Enabled = mode == DialogMode.Normal;
520        instancesTreeView.Enabled = mode == DialogMode.Normal;
521        instancesTreeView.Visible = mode == DialogMode.Normal || mode == DialogMode.CreatingExperiment || mode == DialogMode.PreparingExperiment;
522        okButton.Enabled = mode == DialogMode.Normal;
523        okButton.Visible = mode != DialogMode.CreatingExperiment && mode != DialogMode.PreparingExperiment;
524        cancelButton.Enabled = mode != DialogMode.PreparingExperiment;
525        instanceDiscoveryProgressLabel.Visible = mode == DialogMode.DiscoveringInstances;
526        instanceDiscoveryProgressBar.Visible = mode == DialogMode.DiscoveringInstances;
527        experimentCreationProgressBar.Visible = mode == DialogMode.CreatingExperiment || mode == DialogMode.PreparingExperiment;
528      }
529    }
530
531    private void ClearDetailsView() {
532      stringConvertibleArrayView.Visible = false;
533      stringConvertibleArrayView.Content = null;
534      stringConvertibleArrayView.ReadOnly = true;
535      generateButton.Visible = false;
536      detailsTypeLabel.Visible = false;
537      choicesListView.Items.Clear();
538      choicesListView.Enabled = false;
539      choicesListView.Visible = false;
540    }
541
542    private void UpdateVariationsLabel() {
543      variationsLabel.Text = GetNumberOfVariations().ToString("#,#", CultureInfo.CurrentCulture);
544    }
545
546    #region Retrieve parameter combinations
547    private IEnumerable<Dictionary<IValueParameter, int>> GetIntParameterConfigurations() {
548      var configuration = new Dictionary<IValueParameter, int>();
549      var enumerators = new Dictionary<IValueParameter, IEnumerator<int>>();
550      bool finished;
551      do {
552        foreach (var p in intParameters) {
553          if (!enumerators.ContainsKey(p.Key)) {
554            enumerators[p.Key] = p.Value.GetEnumerator();
555            enumerators[p.Key].MoveNext();
556          }
557          configuration[p.Key] = enumerators[p.Key].Current;
558        }
559        yield return configuration;
560
561        finished = true;
562        foreach (var p in intParameters) {
563          if (!enumerators[p.Key].MoveNext()) {
564            enumerators[p.Key] = p.Value.GetEnumerator();
565            enumerators[p.Key].MoveNext();
566          } else {
567            finished = false;
568            break;
569          }
570        }
571      } while (!finished);
572    }
573
574    private IEnumerable<Dictionary<IValueParameter, double>> GetDoubleParameterConfigurations() {
575      var configuration = new Dictionary<IValueParameter, double>();
576      var enumerators = new Dictionary<IValueParameter, IEnumerator<double>>();
577      bool finished;
578      do {
579        foreach (var p in doubleParameters) {
580          if (!enumerators.ContainsKey(p.Key)) {
581            enumerators[p.Key] = p.Value.GetEnumerator();
582            enumerators[p.Key].MoveNext();
583          }
584          configuration[p.Key] = enumerators[p.Key].Current;
585        }
586        yield return configuration;
587
588        finished = true;
589        foreach (var p in doubleParameters) {
590          if (!enumerators[p.Key].MoveNext()) {
591            enumerators[p.Key] = p.Value.GetEnumerator();
592            enumerators[p.Key].MoveNext();
593          } else {
594            finished = false;
595            break;
596          }
597        }
598      } while (!finished);
599    }
600
601    private IEnumerable<Dictionary<IValueParameter, bool>> GetBoolParameterConfigurations() {
602      var configuration = new Dictionary<IValueParameter, bool>();
603      bool finished;
604      do {
605        finished = true;
606        foreach (var p in boolParameters) {
607          if (!configuration.ContainsKey(p)) configuration.Add(p, false);
608          else {
609            if (configuration[p]) {
610              configuration[p] = false;
611            } else {
612              configuration[p] = true;
613              finished = false;
614              break;
615            }
616          }
617        }
618        yield return configuration;
619      } while (!finished);
620    }
621
622    private IEnumerable<Dictionary<IValueParameter, IItem>> GetMultipleChoiceConfigurations() {
623      var configuration = new Dictionary<IValueParameter, IItem>();
624      var enumerators = new Dictionary<IValueParameter, IEnumerator<IItem>>();
625      bool finished;
626      do {
627        foreach (var p in multipleChoiceParameters.Keys.ToArray()) {
628          if (!enumerators.ContainsKey(p)) {
629            enumerators.Add(p, multipleChoiceParameters[p].GetEnumerator());
630            if (!enumerators[p].MoveNext()) {
631              multipleChoiceParameters.Remove(p);
632              continue;
633            }
634          }
635          configuration[p] = enumerators[p].Current;
636        }
637
638        finished = true;
639        foreach (var p in multipleChoiceParameters.Keys) {
640          if (!enumerators[p].MoveNext()) {
641            enumerators[p] = multipleChoiceParameters[p].GetEnumerator();
642            enumerators[p].MoveNext();
643          } else {
644            finished = false;
645            break;
646          }
647        }
648        yield return configuration;
649      } while (!finished);
650    }
651    #endregion
652    #endregion
653
654    #region Background workers
655    #region Instance discovery
656    private void instanceDiscoveryBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
657      instanceDiscoveryBackgroundWorker.ReportProgress(0, "Finding instance providers...");
658      var instanceProviders = ProblemInstanceManager.GetProviders(((IAlgorithm)Optimizer).Problem).ToArray();
659      var nodes = new List<TreeNode>(instanceProviders.Length);
660      for (int i = 0; i < instanceProviders.Length; i++) {
661        var provider = instanceProviders[i];
662        var providerNode = new TreeNode(provider.Name) { Tag = provider };
663        var descriptors = ProblemInstanceManager.GetDataDescriptors(provider);
664        foreach (var desc in descriptors) {
665          #region Check cancellation request
666          if (instanceDiscoveryBackgroundWorker.CancellationPending) {
667            e.Cancel = true;
668            e.Result = nodes.ToArray();
669            return;
670          }
671          #endregion
672          var node = new TreeNode(desc.Name) { Tag = desc };
673          providerNode.Nodes.Add(node);
674          if (providerNode.Nodes.Count == 1)
675            nodes.Add(providerNode);
676        }
677        double progress = nodes.Count > 0 ? i / (double)nodes.Count : 0.0;
678        instanceDiscoveryBackgroundWorker.ReportProgress((int)(100 * progress), provider.Name);
679      }
680      e.Result = nodes.ToArray();
681      instanceDiscoveryBackgroundWorker.ReportProgress(100, string.Empty);
682    }
683
684    private void instanceDiscoveryBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
685      if (instanceDiscoveryProgressBar.Value != e.ProgressPercentage)
686        instanceDiscoveryProgressBar.Value = e.ProgressPercentage;
687      instanceDiscoveryProgressLabel.Text = (string)e.UserState;
688    }
689
690    private void instanceDiscoveryBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
691      try {
692        if (((TreeNode[])e.Result).Length > 0) {
693          instancesTreeView.Nodes.AddRange((TreeNode[])e.Result);
694          foreach (TreeNode node in instancesTreeView.Nodes)
695            node.Collapse();
696        }
697        selectNoneCheckBox.Checked = true;
698      } catch { }
699      try {
700        SetMode(DialogMode.Normal);
701        if (e.Error != null) MessageBox.Show(e.Error.Message, "Error occurred", MessageBoxButtons.OK, MessageBoxIcon.Error);
702      } catch { }
703    }
704    #endregion
705
706    #region Experiment creation
707    private void experimentCreationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
708      backgroundWorkerWaitHandle.Set(); // notify the ok button that we're busy now
709      failedInstances = new StringBuilder();
710      var localExperiment = new Experiment();
711
712      int counter = 0, totalVariations = GetNumberOfVariations();
713      int totalInstances = instances.Values.SelectMany(x => x).Count();
714      if (totalInstances == 0) {
715        try {
716          AddParameterVariations(Optimizer, localExperiment, ref counter, totalVariations);
717        } catch (OperationCanceledException) {
718          e.Cancel = true;
719          return;
720        }
721        experimentCreationBackgroundWorker.ReportProgress(100, string.Empty);
722      } else {
723        foreach (var provider in instances.Keys) {
724          foreach (var descriptor in instances[provider]) {
725            var algorithm = (IAlgorithm)Optimizer.Clone();
726            bool failed = false;
727            try {
728              ProblemInstanceManager.LoadData(provider, descriptor, (IProblemInstanceConsumer)algorithm.Problem);
729            } catch (Exception ex) {
730              failedInstances.AppendLine(descriptor.Name + ": " + ex.Message);
731              failed = true;
732            }
733            if (!failed) {
734              try {
735                if (totalInstances > 1 && totalVariations / totalInstances > 1) {
736                  var experiment = new Experiment(descriptor.Name);
737                  AddParameterVariations(algorithm, experiment, ref counter, totalVariations);
738                  localExperiment.Optimizers.Add(experiment);
739                } else {
740                  AddParameterVariations(algorithm, localExperiment, ref counter, totalVariations);
741                }
742              } catch (OperationCanceledException) {
743                e.Cancel = true;
744                return;
745              }
746            } else experimentCreationBackgroundWorker.ReportProgress((int)Math.Round((100.0 * counter) / totalVariations), "Loading failed (" + descriptor.Name + ")");
747          }
748        }
749      }
750      // this step can take some time
751      SetMode(DialogMode.PreparingExperiment);
752      experimentCreationBackgroundWorker.ReportProgress(-1);
753      localExperiment.Prepare(true);
754      experimentCreationBackgroundWorker.ReportProgress(100);
755      Experiment = localExperiment;
756    }
757
758    private void AddParameterVariations(IOptimizer optimizer, Experiment localExperiment, ref int counter, int totalVariations) {
759      var variations = CalculateParameterVariations(optimizer);
760      foreach (var v in variations) {
761        if (experimentCreationBackgroundWorker.CancellationPending)
762          throw new OperationCanceledException();
763        AddOptimizer(v, localExperiment);
764        counter++;
765        experimentCreationBackgroundWorker.ReportProgress((int)Math.Round((100.0 * counter) / totalVariations), string.Empty);
766      }
767    }
768
769    private IEnumerable<IOptimizer> CalculateParameterVariations(IOptimizer optimizer) {
770      if (!boolParameters.Any() && !intParameters.Any() && !doubleParameters.Any() && !multipleChoiceParameters.Any()) {
771        var o = (IOptimizer)optimizer.Clone();
772        o.Runs.Clear();
773        yield return o;
774        yield break;
775      }
776      bool finished;
777      var mcEnumerator = GetMultipleChoiceConfigurations().GetEnumerator();
778      var boolEnumerator = GetBoolParameterConfigurations().GetEnumerator();
779      var intEnumerator = GetIntParameterConfigurations().GetEnumerator();
780      var doubleEnumerator = GetDoubleParameterConfigurations().GetEnumerator();
781      mcEnumerator.MoveNext(); boolEnumerator.MoveNext(); intEnumerator.MoveNext(); doubleEnumerator.MoveNext();
782      do {
783        var variant = (IAlgorithm)optimizer.Clone();
784        variant.Runs.Clear();
785        variant.Name += " {";
786        finished = true;
787        if (doubleParameters.Any()) {
788          foreach (var d in doubleEnumerator.Current) {
789            var value = (ValueTypeValue<double>)((IValueParameter)variant.Parameters[d.Key.Name]).Value;
790            value.Value = d.Value;
791            variant.Name += d.Key.Name + "=" + d.Value.ToString() + ", ";
792          }
793          if (finished) {
794            if (doubleEnumerator.MoveNext()) {
795              finished = false;
796            } else {
797              doubleEnumerator = GetDoubleParameterConfigurations().GetEnumerator();
798              doubleEnumerator.MoveNext();
799            }
800          }
801        }
802        if (intParameters.Any()) {
803          foreach (var i in intEnumerator.Current) {
804            var value = (ValueTypeValue<int>)((IValueParameter)variant.Parameters[i.Key.Name]).Value;
805            value.Value = i.Value;
806            variant.Name += i.Key.Name + "=" + i.Value.ToString() + ", ";
807          }
808          if (finished) {
809            if (intEnumerator.MoveNext()) {
810              finished = false;
811            } else {
812              intEnumerator = GetIntParameterConfigurations().GetEnumerator();
813              intEnumerator.MoveNext();
814            }
815          }
816        }
817        if (boolParameters.Any()) {
818          foreach (var b in boolEnumerator.Current) {
819            var value = (ValueTypeValue<bool>)((IValueParameter)variant.Parameters[b.Key.Name]).Value;
820            value.Value = b.Value;
821            variant.Name += b.Key.Name + "=" + b.Value.ToString() + ", ";
822          }
823          if (finished) {
824            if (boolEnumerator.MoveNext()) {
825              finished = false;
826            } else {
827              boolEnumerator = GetBoolParameterConfigurations().GetEnumerator();
828              boolEnumerator.MoveNext();
829            }
830          }
831        }
832        if (multipleChoiceParameters.Any()) {
833          foreach (var m in mcEnumerator.Current) {
834            dynamic variantParam = variant.Parameters[m.Key.Name];
835            if (m.Value == optionalNullChoice) {
836              variantParam.Value = null;
837              variant.Name += m.Key.Name + "=null, ";
838              continue;
839            }
840            var variantEnumerator = ((IEnumerable<object>)variantParam.ValidValues).GetEnumerator();
841            var originalEnumerator = ((IEnumerable<object>)((dynamic)m.Key).ValidValues).GetEnumerator();
842            while (variantEnumerator.MoveNext() && originalEnumerator.MoveNext()) {
843              if (m.Value == (IItem)originalEnumerator.Current) {
844                variantParam.Value = (dynamic)variantEnumerator.Current;
845                if (m.Value is INamedItem)
846                  variant.Name += m.Key.Name + "=" + ((INamedItem)m.Value).Name + ", ";
847                else variant.Name += m.Key.Name + "=" + m.Value.ToString() + ", ";
848                break;
849              }
850            }
851          }
852          if (finished) {
853            if (mcEnumerator.MoveNext()) {
854              finished = false;
855            } else {
856              mcEnumerator = GetMultipleChoiceConfigurations().GetEnumerator();
857              mcEnumerator.MoveNext();
858            }
859          }
860        }
861        variant.Name = variant.Name.Substring(0, variant.Name.Length - 2) + "}";
862        yield return variant;
863      } while (!finished);
864    }
865
866    private void experimentCreationBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
867      if (e.ProgressPercentage >= 0 && e.ProgressPercentage <= 100) {
868        experimentCreationProgressBar.Style = ProgressBarStyle.Continuous;
869        experimentCreationProgressBar.Value = e.ProgressPercentage;
870      } else {
871        experimentCreationProgressBar.Style = ProgressBarStyle.Marquee;
872      }
873    }
874
875    private void experimentCreationBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
876      try {
877        SetMode(DialogMode.Normal);
878        if (e.Error != null) MessageBox.Show(e.Error.Message, "Error occurred", MessageBoxButtons.OK, MessageBoxIcon.Error);
879        if (failedInstances.Length > 0) MessageBox.Show("Some instances could not be loaded: " + Environment.NewLine + failedInstances.ToString(), "Some instances failed to load", MessageBoxButtons.OK, MessageBoxIcon.Error);
880        if (!e.Cancelled && e.Error == null) {
881          DialogResult = System.Windows.Forms.DialogResult.OK;
882          Close();
883        }
884      } catch { }
885    }
886    #endregion
887    #endregion
888  }
889}
Note: See TracBrowser for help on using the repository browser.