#region License Information
/* HeuristicLab
* Copyright (C) 2002-2017 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 {
[View("CreateExperiment View")]
[Content(typeof(IAlgorithm), false)]
public partial class CreateExperimentView : AsynchronousContentView {
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 new IAlgorithm Content {
get { return (IAlgorithm)base.Content; }
set { base.Content = value; }
}
public CreateExperimentView() {
InitializeComponent();
engineComboBox.DataSource = ApplicationManager.Manager.GetInstances().ToArray();
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 };
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(Content.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
protected override void OnContentChanged() {
base.OnContentChanged();
if (Content != null && Content.Problem != null) {
parameterConfigurationTreeView.Content = parameterConfigurationTree = new ParameterConfigurationTree(Content, Content.Problem);
parameterConfigurationTree.CombinationsCountChanged += (o, args) => UpdateCombinationsCount();
experimentFactory.ExperimentGenerationProgressChanged += (o, args) => progress.ProgressValue = experimentFactory.ExperimentGenerationProgress;
} else {
configurationTabControl.TabPages.Remove(problemInstancesTabPage);
SetEnabledStateOfControls();
}
}
protected override void OnClosing(FormClosingEventArgs e) {
cts.Cancel();
base.OnClosing(e);
}
#region Events
private void createBatchRunCheckBox_CheckedChanged(object sender, EventArgs e) {
repetitionsNumericUpDown.Enabled = createBatchRun = createBatchRunCheckBox.Checked;
}
private void repetitionsNumericUpDown_Validated(object sender, EventArgs e) {
if (repetitionsNumericUpDown.Text == string.Empty)
repetitionsNumericUpDown.Text = repetitionsNumericUpDown.Value.ToString();
repetitions = (int)repetitionsNumericUpDown.Value;
}
private void engineComboBox_SelectedIndexChanged(object sender, 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 generateButton_Click(object sender, EventArgs e) {
experimentGenerator = Task.Factory.StartNew(() => {
StartProgressView();
var engineAlgorithm = Content as EngineAlgorithm;
if (engineAlgorithm != null) engineAlgorithm.Engine = engine;
try {
var experiment = experimentFactory.GenerateExperiment(
Content, parameterConfigurationTree, createBatchRun,
createBatchRun ? repetitions : 0, selectedProblemInstanceProviders, cts.Token);
MainFormManager.MainForm.ShowContent(experiment);
} finally {
FinishProgressView();
}
}, cts.Token);
experimentGenerator.ContinueWith(t => {
experimentGenerator = null;
}, 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 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 = Math.Max(1, selectedProblemInstanceProviders.Values.Sum(x => x.Count));
generateButton.Text = string.Format("&Create Experiment (Combinations: {0})", combinationsCount * instanceCount);
}
private void StartProgressView() {
progress.Start();
var mainForm = MainFormManager.GetMainForm();
mainForm.AddOperationProgressToView(this, progress);
}
private void FinishProgressView() {
var mainForm = MainFormManager.GetMainForm();
mainForm.RemoveOperationProgressFromView(this);
progress.Finish();
}
private void ReportError(Exception e) {
if (InvokeRequired) {
Invoke(new Action(ReportError), e);
} else {
ErrorHandling.ShowErrorDialog(this, "An error occurred generating the experiment.", e);
}
}
#endregion
}
}