#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HeuristicLab.Core;
using HeuristicLab.MainForm;
using HeuristicLab.MainForm.WindowsForms;
using HeuristicLab.Optimization;
using HeuristicLab.PluginInfrastructure;
using HeuristicLab.Problems.Instances;
namespace HeuristicLab.Encodings.ParameterConfigurationEncoding.Views {
public partial class CreateExperimentDialogV2 : Form {
private readonly IAlgorithm algorithm;
private readonly ExperimentFactory experimentFactory;
private readonly Progress progress;
private ParameterConfigurationTree parameterConfigurationTree;
private bool createBatchRun;
private int repetitions;
private IEngine engine;
private Task experimentGenerator;
private CancellationTokenSource cts;
private Dictionary> problemInstanceProviders;
private Dictionary> selectedProblemInstanceProviders;
public Experiment Experiment { get; private set; }
public CreateExperimentDialogV2() : this(null, null) { }
public CreateExperimentDialogV2(IAlgorithm algorithm, IEnumerable engines) {
InitializeComponent();
if (algorithm != null && engines != null) {
this.algorithm = (IAlgorithm)algorithm.Clone();
foreach (var engine in engines) engineComboBox.Items.Add(engine);
if (engineComboBox.SelectedItem == null) {
engineComboBox.SelectedIndex = 0;
engine = (IEngine)engineComboBox.SelectedItem;
}
}
createBatchRun = createBatchRunCheckBox.Checked;
repetitions = (int)repetitionsNumericUpDown.Value;
selectedProblemInstanceProviders = new Dictionary>();
progress = new Progress {
CanBeCanceled = true,
ProgressState = ProgressState.Finished
};
progress.CancelRequested += (sender, args) => cts.Cancel();
progress.ProgressValueChanged += (sender, args) => progress.Status = string.Format("Generating experiment. Please be patient. ({0} %)", (int)(progress.ProgressValue * 100));
experimentFactory = new ExperimentFactory();
cts = new CancellationTokenSource();
}
#region Background worker
private void instanceDiscoveryBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
var instanceProviders = new Dictionary>();
foreach (var provider in ProblemInstanceManager.GetProviders(algorithm.Problem))
instanceProviders[provider] = new HashSet(ProblemInstanceManager.GetDataDescriptors(provider));
e.Result = instanceProviders;
}
private void instanceDiscoveryBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
problemInstanceProviders = (Dictionary>)e.Result;
libraryComboBox.DisplayMember = "Name";
libraryComboBox.DataSource = problemInstanceProviders.Keys.ToList();
libraryComboBox.Enabled = true;
}
#endregion
#region Events
private void CreateExperimentDialogV2_Load(object sender, System.EventArgs e) {
if (algorithm.Problem != null) {
parameterConfigurationTreeView.Content = parameterConfigurationTree = new ParameterConfigurationTree(algorithm, algorithm.Problem);
parameterConfigurationTree.CombinationsCountChanged += (o, args) => UpdateCombinationsCount();
experimentFactory.ExperimentGenerationProgressChanged += (o, args) => progress.ProgressValue = experimentFactory.ExperimentGenerationProgress;
new ProgressView(parameterConfigurationTreeView, progress) { CancelTimeoutMs = 10000 };
} else {
configurationTabControl.TabPages.Remove(problemInstancesTabPage);
SetEnabledStateOfControls(false);
}
}
private void CreateExperimentDialogV2_FormClosing(object sender, FormClosingEventArgs e) {
if (experimentGenerator != null) e.Cancel = true;
}
private void createBatchRunCheckBox_CheckedChanged(object sender, System.EventArgs e) {
repetitionsNumericUpDown.Enabled = createBatchRun = createBatchRunCheckBox.Checked;
}
private void repetitionsNumericUpDown_Validated(object sender, System.EventArgs e) {
if (repetitionsNumericUpDown.Text == string.Empty)
repetitionsNumericUpDown.Text = repetitionsNumericUpDown.Value.ToString();
repetitions = (int)repetitionsNumericUpDown.Value;
}
private void engineComboBox_SelectedIndexChanged(object sender, System.EventArgs e) {
engine = (IEngine)engineComboBox.SelectedItem;
}
private void configurationTabControl_SelectedIndexChanged(object sender, EventArgs e) {
if (configurationTabControl.SelectedTab == problemInstancesTabPage && problemInstanceProviders == null) {
libraryComboBox.Enabled = false;
instanceDiscoveryBackgroundWorker.RunWorkerAsync();
}
}
private void libraryComboBox_SelectedIndexChanged(object sender, EventArgs e) {
UpdateTreeView((IProblemInstanceProvider)libraryComboBox.SelectedItem);
}
private void instanceTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
if (e.Action != TreeViewAction.Unknown) {
var provider = e.Node.Tag as IProblemInstanceProvider;
if (provider != null) {
if (e.Node.Checked) {
if (!selectedProblemInstanceProviders.ContainsKey(provider))
selectedProblemInstanceProviders[provider] = new HashSet();
foreach (TreeNode node in e.Node.Nodes) {
selectedProblemInstanceProviders[provider].Add((IDataDescriptor)node.Tag);
node.Checked = e.Node.Checked;
}
} else {
selectedProblemInstanceProviders[provider].Clear();
foreach (TreeNode node in e.Node.Nodes) {
node.Checked = e.Node.Checked;
}
}
} else {
provider = (IProblemInstanceProvider)e.Node.Parent.Tag;
if (!selectedProblemInstanceProviders.ContainsKey(provider))
selectedProblemInstanceProviders[provider] = new HashSet();
if (e.Node.Checked) {
selectedProblemInstanceProviders[provider].Add((IDataDescriptor)e.Node.Tag);
var instances = new TreeNode[e.Node.Parent.Nodes.Count];
e.Node.Parent.Nodes.CopyTo(instances, 0);
e.Node.Parent.Checked = instances.All(x => x.Checked);
} else {
selectedProblemInstanceProviders[provider].Remove((IDataDescriptor)e.Node.Tag);
e.Node.Parent.Checked = e.Node.Checked;
}
}
UpdateCombinationsCount();
}
}
private void okButton_Click(object sender, System.EventArgs e) {
configurationTabControl.SelectedTab = parameterConfigurationTabPage;
experimentGenerator = Task.Factory.StartNew(() => {
StartProgressView();
var engineAlgorithm = algorithm as EngineAlgorithm;
if (engineAlgorithm != null) engineAlgorithm.Engine = engine;
try {
Experiment = createBatchRun ? experimentFactory.GenerateExperiment(engineAlgorithm, parameterConfigurationTree, true, repetitions, selectedProblemInstanceProviders, cts.Token)
: experimentFactory.GenerateExperiment(engineAlgorithm, parameterConfigurationTree, false, 0, selectedProblemInstanceProviders, cts.Token);
}
finally { FinishProgressView(); }
}, cts.Token);
experimentGenerator.ContinueWith(t => {
experimentGenerator = null;
CloseDialog();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
experimentGenerator.ContinueWith(t => {
experimentGenerator = null;
if (t.IsCanceled) cts = new CancellationTokenSource();
if (t.IsFaulted) {
ReportError(t.Exception.Flatten());
t.Exception.Flatten().Handle(ex => true);
}
}, TaskContinuationOptions.NotOnRanToCompletion);
}
#endregion
#region Helpers
private void SetEnabledStateOfControls(bool state) {
createBatchRunCheckBox.Enabled = state;
repetitionsNumericUpDown.Enabled = state;
engineComboBox.Enabled = state;
okButton.Enabled = state;
cancelButton.Enabled = state;
}
private void UpdateTreeView(IProblemInstanceProvider provider) {
instanceTreeView.Nodes.Clear();
var rootNode = new TreeNode("All") { Tag = provider };
TreeNode[] instances = problemInstanceProviders[provider]
.Select(x => new TreeNode(x.Name) {
Tag = x,
Checked = selectedProblemInstanceProviders.ContainsKey(provider)
&& selectedProblemInstanceProviders[provider].Contains(x)
})
.ToArray();
rootNode.Checked = instances.All(x => x.Checked);
rootNode.Nodes.AddRange(instances);
rootNode.ExpandAll();
instanceTreeView.Nodes.Add(rootNode);
}
private void UpdateCombinationsCount() {
var combinationsCount = parameterConfigurationTree.CombinationsCount;
var instanceCount = 1 + selectedProblemInstanceProviders.Values.Sum(x => x.Count);
combinationsCountLabel.Text = (combinationsCount * instanceCount).ToString();
}
private void StartProgressView() {
if (InvokeRequired) {
Invoke(new Action(StartProgressView));
} else {
SetEnabledStateOfControls(false);
problemInstancesTabPage.Enabled = false;
progress.ProgressValue = 0;
progress.ProgressState = ProgressState.Started;
}
}
private void FinishProgressView() {
if (InvokeRequired) {
Invoke(new Action(FinishProgressView));
} else {
progress.Finish();
problemInstancesTabPage.Enabled = true;
SetEnabledStateOfControls(true);
}
}
private void ReportError(Exception e) {
if (InvokeRequired) {
Invoke(new Action(ReportError), e);
} else {
ErrorHandling.ShowErrorDialog(this, "An error occurred generating the experiment.", e);
}
}
private void CloseDialog() {
if (InvokeRequired) {
Invoke(new Action(CloseDialog));
} else {
this.DialogResult = DialogResult.OK;
this.Close();
}
}
#endregion
}
}