#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.Linq;
using System.Threading;
using System.Threading.Tasks;
using HEAL.Attic;
using HeuristicLab.Collections;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
namespace HeuristicLab.Analysis {
///
/// A run in which an algorithm is executed for a certain maximum time only.
///
[Item("Iterated Algorithm", "An algorithm that repeats an algorithm until either a certain target value is reached or a maximum budget is exceeded.")]
[Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 116)]
[StorableType("787AF25E-46FF-4FBF-A2ED-011E7F41AF58")]
public sealed class IteratedAlgorithm : Algorithm, IStorableContent {
private const string ExecutionTimeResultName = "Execution Time";
private const string BestQualityResultName = "BestQuality";
private const string RandomRestartsResultName = "RandomRestarts";
private const string EvaluatedSolutionsResultName = "EvaluatedSolutions";
private const string EvaluatedMovesResultName = "EvaluatedMoves";
private const string QualityPerClockResultName = "QualityPerClock";
private const string QualityPerEvaluationsResultName = "QualityPerEvaluations";
private const string EvaluationsResultName = "Evaluations";
public string Filename { get; set; }
public override Type ProblemType { get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); } }
public IValueParameter MaximumExecutionTimeParameter {
get { return (IValueParameter)Parameters["MaximumExecutionTime"]; }
}
public IValueParameter MaximumEvaluationsParameter {
get { return (IValueParameter)Parameters["MaximumEvaluations"]; }
}
public IValueParameter TargetQualityParameter {
get { return (IValueParameter)Parameters["TargetQuality"]; }
}
private IFixedValueParameter MoveCostPerSolutionParameter {
get { return (IFixedValueParameter)Parameters["MoveCostPerSolution"]; }
}
private IFixedValueParameter StoreSolutionInRunParameter {
get { return (IFixedValueParameter)Parameters["StoreSolutionInRun"]; }
}
private IValueParameter AlgorithmParameter {
get { return (IValueParameter)Parameters["Algorithm"]; }
}
private IFixedValueParameter AnalyzerParameter {
get { return (IFixedValueParameter)Parameters["Analyzer"]; }
}
[Storable]
private ResultCollection results;
public override ResultCollection Results {
get { return results; }
}
[Storable]
private QualityPerClockAnalyzer perClockAnalyzer;
public QualityPerClockAnalyzer PerClockAnalyzer {
get { return perClockAnalyzer; }
}
[Storable]
private QualityPerEvaluationsAnalyzer perEvaluationsAnalyzer;
public QualityPerEvaluationsAnalyzer PerEvaluationsAnalyzer {
get { return perEvaluationsAnalyzer; }
}
[Storable]
private BestScopeSolutionAnalyzer bestSolutionAnalyzer;
public BestScopeSolutionAnalyzer BestSolutionAnalyzer {
get { return bestSolutionAnalyzer; }
}
public double MoveCostPerSolution {
get { return MoveCostPerSolutionParameter.Value.Value; }
set { MoveCostPerSolutionParameter.Value.Value = value; }
}
public bool StoreSolutionInRun {
get { return StoreSolutionInRunParameter.Value.Value; }
set { StoreSolutionInRunParameter.Value.Value = value; }
}
// algorithm will be set in AfterDeserialization to the value of the parameter
private IAlgorithm algorithm;
public IAlgorithm Algorithm {
get { return algorithm; }
set {
if (algorithm == value) return;
if (algorithm != null) {
DeregisterAlgorithmEvents();
RemoveAlgorithmAnalyzers();
}
algorithm = value;
if (algorithm != null) {
if (algorithm.ExecutionState != ExecutionState.Prepared)
algorithm.Prepare(true);
if (Problem != null)
algorithm.Problem = Problem;
RegisterAlgorithmEvents();
AddAlgorithmAnalyzers();
HandleAlgorithmMaximumEvaluationsChanged();
HandleAlgorithmTargetQualityChanged();
}
if (AlgorithmParameter.Value != algorithm)
AlgorithmParameter.Value = algorithm;
Prepare();
}
}
public MultiAnalyzer Analyzer {
get { return AnalyzerParameter.Value; }
}
private bool Maximization {
get { return Problem != null && ((IValueParameter)((ISingleObjectiveHeuristicOptimizationProblem)Problem).MaximizationParameter).Value.Value; }
}
private bool IsFinished {
get {
var executionTime = Results.ContainsKey(ExecutionTimeResultName) ? ((TimeSpanValue)Results[ExecutionTimeResultName].Value).Value : TimeSpan.Zero;
var evaluations = Results.ContainsKey(EvaluationsResultName) ? ((DoubleValue)Results[EvaluationsResultName].Value).Value : 0;
var bestQuality = Results.ContainsKey(BestQualityResultName) ? ((DoubleValue)Results[BestQualityResultName].Value).Value
: (Maximization ? double.MinValue : double.MaxValue);
var targetValue = TargetQualityParameter.Value != null ? TargetQualityParameter.Value.Value
: Maximization ? double.MaxValue : double.MinValue;
var timeHit = MaximumExecutionTimeParameter.Value != null && executionTime >= MaximumExecutionTimeParameter.Value.Value;
var evalHit = MaximumEvaluationsParameter.Value != null && evaluations >= MaximumEvaluationsParameter.Value.Value;
var targetHit = Maximization && bestQuality >= targetValue || !Maximization && bestQuality <= targetValue;
return forceStop || timeHit || evalHit || targetHit;
}
}
[StorableConstructor]
private IteratedAlgorithm(StorableConstructorFlag _) : base(_) { }
private IteratedAlgorithm(IteratedAlgorithm original, Cloner cloner)
: base(original, cloner) {
results = cloner.Clone(original.Results);
perClockAnalyzer = cloner.Clone(original.perClockAnalyzer);
perEvaluationsAnalyzer = cloner.Clone(original.perEvaluationsAnalyzer);
bestSolutionAnalyzer = cloner.Clone(original.bestSolutionAnalyzer);
algorithm = cloner.Clone(original.algorithm);
RegisterEventHandlers();
}
public IteratedAlgorithm()
: base() {
results = new ResultCollection();
Parameters.Add(new FixedValueParameter("Analyzer", "Analyzers that should be called in addition to the default algorithm analyzers.", new MultiAnalyzer()));
Parameters.Add(new OptionalValueParameter("MaximumExecutionTime", "The maximum wall-clock time that the algorithm should run."));
Parameters.Add(new OptionalValueParameter("MaximumEvaluations", "The maximum number of function evaluations that the algorithm should run.", new IntValue(100000000)));
Parameters.Add(new OptionalValueParameter("TargetQuality", "The target quality that the algorithm should run for."));
Parameters.Add(new FixedValueParameter("MoveCostPerSolution", "The amount of solution evaluation equivalents of a single move. Use 1 for a black-box scenario.", new DoubleValue(1)));
Parameters.Add(new FixedValueParameter("StoreSolutionInRun", "Whether the solution data types should be kept in the run."));
Parameters.Add(new ValueParameter("Algorithm", "The algorithm to iterate.") { GetsCollected = false }); // due to storage efficiency, by default we don't want to store the algorithm instance in the run
perClockAnalyzer = new QualityPerClockAnalyzer();
perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
bestSolutionAnalyzer = new BestScopeSolutionAnalyzer();
Analyzer.Operators.Add(perClockAnalyzer, true);
Analyzer.Operators.Add(perEvaluationsAnalyzer, true);
Analyzer.Operators.Add(bestSolutionAnalyzer, StoreSolutionInRun);
RegisterEventHandlers();
}
public override IDeepCloneable Clone(Cloner cloner) {
if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
return new IteratedAlgorithm(this, cloner);
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
algorithm = AlgorithmParameter.Value;
// BackwardsCompatibility3.3
#region Backwards compatible code, remove with 3.4
if (Parameters.ContainsKey("TargetValue")) {
var target = ((OptionalValueParameter)Parameters["TargetValue"]).Value;
Parameters.Remove("TargetValue");
Parameters.Add(new OptionalValueParameter("TargetQuality", "The target quality that the algorithm should run for.", target));
}
if (!Parameters.ContainsKey("Analyzer")) {
Parameters.Add(new FixedValueParameter("Analyzer", "Analyzers that should be called in addition to the default algorithm analyzers.", new MultiAnalyzer()));
Analyzer.Operators.Add(perClockAnalyzer, true);
Analyzer.Operators.Add(perEvaluationsAnalyzer, true);
if (Algorithm != null && Algorithm.Parameters.ContainsKey("Analyzer")) {
var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam != null) {
analyzerParam.Value.Operators.Remove(perClockAnalyzer);
analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
} else {
var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam2 != null) {
analyzerParam2.Value.Operators.Remove(perClockAnalyzer);
analyzerParam2.Value.Operators.Remove(perEvaluationsAnalyzer);
}
}
AddAlgorithmAnalyzers();
}
}
if (bestSolutionAnalyzer == null) {
bestSolutionAnalyzer = new BestScopeSolutionAnalyzer();
Analyzer.Operators.Add(bestSolutionAnalyzer, StoreSolutionInRun);
}
#endregion
RegisterEventHandlers();
}
#region Register Event Handlers
protected override void RegisterProblemEvents() {
var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter;
if (bkParam != null) {
bkParam.ValueChanged += Problem_BestKnownQualityParameter_ValueChanged;
}
base.RegisterProblemEvents();
}
protected override void DeregisterProblemEvents() {
base.DeregisterProblemEvents();
var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter;
if (bkParam != null) {
bkParam.ValueChanged -= Problem_BestKnownQualityParameter_ValueChanged;
}
}
private void RegisterAlgorithmEvents() {
Algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
Algorithm.Paused += Algorithm_Paused;
Algorithm.Stopped += Algorithm_Stopped;
Algorithm.ProblemChanged += Algorithm_ProblemChanged;
#region MaximumEvaluations
IParameter param;
if (Algorithm.Parameters.TryGetValue("MaximumEvaluations", out param)) {
var intFixedValueParam = (param as IFixedValueParameter);
if (intFixedValueParam != null) {
intFixedValueParam.Value.ValueChanged += AlgorithmMaximumEvaluationsOnValueChanged;
} else {
var intValueParam = (param as IValueParameter);
if (intValueParam != null) {
intValueParam.ValueChanged += AlgorithmMaximumEvaluationsParameterOnChanged;
if (intValueParam.Value != null) intValueParam.Value.ValueChanged += AlgorithmMaximumEvaluationsOnValueChanged;
}
}
}
#endregion
#region TargetQuality
if (Algorithm.Parameters.TryGetValue("TargetQuality", out param)) {
var intValueParam = (param as IValueParameter);
if (intValueParam != null) {
intValueParam.ValueChanged += AlgorithmTargetQualityParameterOnChanged;
if (intValueParam.Value != null) intValueParam.Value.ValueChanged += AlgorithmTargetQualityOnValueChanged;
}
}
#endregion
}
private void DeregisterAlgorithmEvents() {
Algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
Algorithm.Paused -= Algorithm_Paused;
Algorithm.Stopped -= Algorithm_Stopped;
Algorithm.ProblemChanged -= Algorithm_ProblemChanged;
#region MaximumEvaluations
IParameter param;
if (Algorithm.Parameters.TryGetValue("MaximumEvaluations", out param)) {
var intFixedValueParam = (param as IFixedValueParameter);
if (intFixedValueParam != null) {
intFixedValueParam.Value.ValueChanged -= AlgorithmMaximumEvaluationsOnValueChanged;
} else {
var intValueParam = (param as IValueParameter);
if (intValueParam != null) {
intValueParam.ValueChanged -= AlgorithmMaximumEvaluationsParameterOnChanged;
if (intValueParam.Value != null) intValueParam.Value.ValueChanged -= AlgorithmMaximumEvaluationsOnValueChanged;
}
}
}
#endregion
#region TargetQuality
if (Algorithm.Parameters.TryGetValue("TargetQuality", out param)) {
var intValueParam = (param as IValueParameter);
if (intValueParam != null) {
intValueParam.ValueChanged -= AlgorithmTargetQualityParameterOnChanged;
if (intValueParam.Value != null) intValueParam.Value.ValueChanged -= AlgorithmTargetQualityOnValueChanged;
}
}
#endregion
}
#endregion
private void RegisterEventHandlers() {
if (Algorithm != null) RegisterAlgorithmEvents();
if (Problem != null) RegisterProblemEvents();
AlgorithmParameter.ValueChanged += AlgorithmParameterOnValueChanged;
StoreSolutionInRunParameter.Value.ValueChanged += StoreSolutionInRunOnValueChanged;
Analyzer.Operators.CollectionReset += AnalyzerOperatorsChanged;
Analyzer.Operators.ItemsAdded += AnalyzerOperatorsChanged;
Analyzer.Operators.ItemsRemoved += AnalyzerOperatorsChanged;
Analyzer.Operators.ItemsReplaced += AnalyzerOperatorsChanged;
MaximumEvaluationsParameter.Value.ValueChanged += MaximumEvaluationsParameterOnValueChanged;
TargetQualityParameter.ValueChanged += TargetQualityParameterChanged;
if (TargetQualityParameter.Value != null) TargetQualityParameter.Value.ValueChanged += TargetQualityParameterOnValueChanged;
}
private bool suppressAnalyzerOperatorEvents = false;
private void AnalyzerOperatorsChanged(object sender, CollectionItemsChangedEventArgs> e) {
if (suppressAnalyzerOperatorEvents) return;
if (!Analyzer.Operators.Contains(perClockAnalyzer)) {
suppressAnalyzerOperatorEvents = true;
try { Analyzer.Operators.Add(perClockAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
}
if (!Analyzer.Operators.Contains(perEvaluationsAnalyzer)) {
suppressAnalyzerOperatorEvents = true;
try { Analyzer.Operators.Add(perEvaluationsAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
}
if (!Analyzer.Operators.Contains(bestSolutionAnalyzer)) {
suppressAnalyzerOperatorEvents = true;
try { Analyzer.Operators.Add(bestSolutionAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
}
}
private void StoreSolutionInRunOnValueChanged(object sender, EventArgs eventArgs) {
Analyzer.Operators.SetItemCheckedState(bestSolutionAnalyzer, StoreSolutionInRun);
}
private void AlgorithmParameterOnValueChanged(object sender, EventArgs eventArgs) {
Algorithm = AlgorithmParameter.Value;
}
#region Prepare, Start, Pause, Stop
public override void Prepare() {
if (Problem == null || Algorithm == null) return;
Algorithm.Prepare(true);
results.Clear();
OnPrepared();
}
public override void Start() {
base.Start();
OnStarted();
Task.Factory.StartNew(Run, null).ContinueWith(t => {
try {
t.Wait();
} catch (AggregateException ex) {
try {
ex.Flatten().Handle(x => x is OperationCanceledException);
} catch (AggregateException remaining) {
if (remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
else OnExceptionOccurred(remaining);
}
}
if (Algorithm.ExecutionState == ExecutionState.Paused) OnPaused();
else OnStopped();
forceStop = false;
});
}
public override void Pause() {
base.Pause();
Algorithm.Pause();
}
private bool forceStop = false;
public override void Stop() {
base.Stop();
if (ExecutionState == ExecutionState.Started) {
forceStop = true;
Algorithm.Stop();
} else if (ExecutionState == ExecutionState.Paused) {
RoundupResults();
Algorithm.Prepare(true);
OnStopped();
}
}
#endregion
private DateTime lastUpdateTime;
private void Run(object state) {
lastUpdateTime = DateTime.UtcNow;
System.Timers.Timer timer = new System.Timers.Timer(250);
timer.AutoReset = true;
timer.Elapsed += timer_Elapsed;
timer.Start();
try {
Run();
} finally {
timer.Elapsed -= timer_Elapsed;
timer.Stop();
ExecutionTime += DateTime.UtcNow - lastUpdateTime;
}
}
private readonly AutoResetEvent algorithmWaitHandle = new AutoResetEvent(false);
private void Run() {
if (!Results.ContainsKey(ExecutionTimeResultName)) Results.Add(new Result(ExecutionTimeResultName, new TimeSpanValue(TimeSpan.Zero)));
if (!Results.ContainsKey(EvaluatedSolutionsResultName)) Results.Add(new Result(EvaluatedSolutionsResultName, new DoubleValue(0)));
if (!Results.ContainsKey(EvaluatedMovesResultName)) Results.Add(new Result(EvaluatedMovesResultName, new DoubleValue(0)));
if (!Results.ContainsKey(EvaluationsResultName)) Results.Add(new Result(EvaluationsResultName, new DoubleValue(0)));
if (!Results.ContainsKey(BestQualityResultName)) Results.Add(new Result(BestQualityResultName, new DoubleValue(double.NaN)));
do {
if (!Results.ContainsKey(RandomRestartsResultName)) Results.Add(new Result(RandomRestartsResultName, new IntValue(0)));
else if (Algorithm.ExecutionState == ExecutionState.Prepared) ((IntValue)Results[RandomRestartsResultName].Value).Value++;
Algorithm.Start();
algorithmWaitHandle.WaitOne();
if (Algorithm.ExecutionState == ExecutionState.Paused) return;
RoundupResults();
Algorithm.Prepare(true);
} while (!IsFinished);
}
private void RoundupResults() {
if (Algorithm == null) return;
var execTime = ((TimeSpanValue)Results[ExecutionTimeResultName].Value);
var solEvals = ((DoubleValue)Results[EvaluatedSolutionsResultName].Value);
var movEvals = ((DoubleValue)Results[EvaluatedMovesResultName].Value);
var restarts = ((IntValue)Results[RandomRestartsResultName].Value);
var evaluations = ((DoubleValue)Results[EvaluationsResultName].Value);
var bestQuality = ((DoubleValue)Results[BestQualityResultName].Value);
var improvement = false;
IResult result;
if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out result)) {
var evals = ((IntValue)result.Value).Value;
evaluations.Value += evals;
solEvals.Value += evals;
}
if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out result)) {
var evals = ((IntValue)result.Value).Value;
evaluations.Value += MoveCostPerSolution * evals;
movEvals.Value += evals;
}
if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out result)) {
var newBestQuality = ((DoubleValue)result.Value).Value;
if (double.IsNaN(bestQuality.Value)
|| Maximization && newBestQuality > bestQuality.Value
|| !Maximization && newBestQuality < bestQuality.Value) {
bestQuality.Value = newBestQuality;
improvement = true;
}
}
if (Algorithm.Results.TryGetValue(perClockAnalyzer.QualityPerClockParameter.ActualName, out result)) UpdateQualityPerClockResult((IndexedDataTable)result.Value, restarts.Value);
if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ActualName, out result)) UpdateQualityPerEvaluationsResult((IndexedDataTable)result.Value, restarts.Value);
if (StoreSolutionInRun) {
foreach (var r in Algorithm.Results) {
if (r.Name == bestSolutionAnalyzer.BestSolutionResultName || r.Name.ToLower().EndsWith("solution") && improvement) {
if (!Results.TryGetValue(r.Name, out result))
Results.Add(new Result(r.Name, (IItem)r.Value.Clone()));
else result.Value = (IItem)r.Value.Clone();
}
}
}
execTime.Value = ExecutionTime;
}
private void UpdateQualityPerClockResult(IndexedDataTable perClock, int restarts) {
IndexedDataTable dt;
if (!Results.ContainsKey(QualityPerClockResultName)) {
dt = (IndexedDataTable)perClock.Clone();
if (!dt.Rows.ContainsKey("Restarts"))
dt.Rows.Add(new IndexedDataRow("Restarts") {
VisualProperties = {
ChartType = DataRowVisualProperties.DataRowChartType.StepLine,
SecondYAxis = true
}
});
foreach (var v in dt.Rows.First().Values)
dt.Rows["Restarts"].Values.Add(Tuple.Create(v.Item1, 0.0));
Results.Add(new Result(QualityPerClockResultName, dt));
} else {
dt = (IndexedDataTable)Results[QualityPerClockResultName].Value;
var qualityValues = dt.Rows.First().Values;
var restartValues = dt.Rows["Restarts"].Values;
var best = qualityValues.Last().Item2;
var execTime = qualityValues.Last().Item1;
var improvement = false;
foreach (var tupl in perClock.Rows.First().Values) {
if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
if (!improvement) {
// the last entry always holds the same value, but with highest execution time
qualityValues.RemoveAt(qualityValues.Count - 1);
restartValues.RemoveAt(restartValues.Count - 1);
improvement = true;
}
qualityValues.Add(Tuple.Create(execTime + tupl.Item1, tupl.Item2));
restartValues.Add(Tuple.Create(execTime + tupl.Item1, (double)restarts));
best = tupl.Item2;
}
}
if (!improvement) {
qualityValues.RemoveAt(qualityValues.Count - 1);
restartValues.RemoveAt(restartValues.Count - 1);
}
var totalExecTime = execTime + perClock.Rows.First().Values.Last().Item1;
qualityValues.Add(Tuple.Create(totalExecTime, best));
restartValues.Add(Tuple.Create(totalExecTime, (double)restarts));
}
}
private void UpdateQualityPerEvaluationsResult(IndexedDataTable perEvaluations, int restarts) {
IndexedDataTable dt;
if (!Results.ContainsKey(QualityPerEvaluationsResultName)) {
dt = (IndexedDataTable)perEvaluations.Clone();
if (!dt.Rows.ContainsKey("Restarts"))
dt.Rows.Add(new IndexedDataRow("Restarts") {
VisualProperties = {
ChartType = DataRowVisualProperties.DataRowChartType.StepLine,
SecondYAxis = true
}
});
foreach (var v in dt.Rows.First().Values)
dt.Rows["Restarts"].Values.Add(Tuple.Create(v.Item1, 0.0));
Results.Add(new Result(QualityPerEvaluationsResultName, dt));
} else {
dt = (IndexedDataTable)Results[QualityPerEvaluationsResultName].Value;
var qualityValues = dt.Rows.First().Values;
var restartValues = dt.Rows["Restarts"].Values;
var best = qualityValues.Last().Item2;
var evaluations = qualityValues.Last().Item1;
var improvement = false;
foreach (var tupl in perEvaluations.Rows.First().Values) {
if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
if (!improvement) {
// the last entry always holds the same value, but with highest evaluations
qualityValues.RemoveAt(qualityValues.Count - 1);
restartValues.RemoveAt(restartValues.Count - 1);
improvement = true;
}
qualityValues.Add(Tuple.Create(evaluations + tupl.Item1, tupl.Item2));
restartValues.Add(Tuple.Create(evaluations + tupl.Item1, (double)restarts));
best = tupl.Item2;
}
}
if (!improvement) {
// add the best quality again as value with highest evaluations
qualityValues.RemoveAt(qualityValues.Count - 1);
restartValues.RemoveAt(restartValues.Count - 1);
}
var totalEvaluations = evaluations + perEvaluations.Rows.First().Values.Last().Item1;
qualityValues.Add(Tuple.Create(totalEvaluations, best));
restartValues.Add(Tuple.Create(totalEvaluations, (double)restarts));
}
}
private void UpdateTargetValueFromBestKnownQuality() {
var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter;
if (bkParam != null && bkParam.Value != null)
TargetQualityParameter.Value = new DoubleValue(bkParam.Value.Value);
else if (bkParam != null && bkParam.Value == null)
TargetQualityParameter.Value = null;
}
private void AddAlgorithmAnalyzers() {
if (Algorithm == null) return;
if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam != null) {
if (analyzerParam.Value.Operators.Contains(Analyzer)) return;
analyzerParam.Value.Operators.Add(Analyzer, true);
} else {
var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam2 == null) return;
if (analyzerParam2.Value.Operators.Contains(Analyzer)) return;
analyzerParam2.Value.Operators.Add(Analyzer, true);
}
}
private void RemoveAlgorithmAnalyzers() {
if (Algorithm == null) return;
if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam != null) {
analyzerParam.Value.Operators.Remove(Analyzer);
} else {
var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter;
if (analyzerParam2 != null) {
analyzerParam2.Value.Operators.Remove(Analyzer);
}
}
}
#region Event Handlers
private void Algorithm_ExceptionOccurred(object sender, EventArgs e) {
OnExceptionOccurred(e.Value);
}
private void Algorithm_Paused(object sender, EventArgs e) {
if (ExecutionState == ExecutionState.Paused) return;
algorithmWaitHandle.Set();
}
private void Algorithm_Stopped(object sender, EventArgs e) {
if (ExecutionState == ExecutionState.Paused) return;
algorithmWaitHandle.Set();
}
private void Algorithm_ProblemChanged(object sender, EventArgs e) {
if (Algorithm.Problem != Problem) Problem = (ISingleObjectiveHeuristicOptimizationProblem)Algorithm.Problem;
AddAlgorithmAnalyzers();
}
private void AlgorithmTargetQualityParameterOnChanged(object sender, EventArgs e) {
var doubleValueParam = (sender as IValueParameter);
if (doubleValueParam.Value != null) doubleValueParam.Value.ValueChanged += AlgorithmTargetQualityOnValueChanged;
HandleAlgorithmTargetQualityChanged();
}
private void AlgorithmTargetQualityOnValueChanged(object sender, EventArgs e) {
HandleAlgorithmTargetQualityChanged();
}
private void AlgorithmMaximumEvaluationsParameterOnChanged(object sender, EventArgs eventArgs) {
var intValueParam = (sender as IValueParameter);
if (intValueParam.Value == null) {
intValueParam.Value = new IntValue();
return;
}
intValueParam.Value.ValueChanged += AlgorithmMaximumEvaluationsOnValueChanged;
HandleAlgorithmMaximumEvaluationsChanged();
}
private void AlgorithmMaximumEvaluationsOnValueChanged(object sender, EventArgs eventArgs) {
var intValue = (IntValue)sender;
HandleAlgorithmMaximumEvaluationsChanged();
}
private void Problem_BestKnownQualityParameter_ValueChanged(object sender, EventArgs e) {
var param = sender as IValueParameter;
if (param != null) {
if (param.Value != null) param.Value.ValueChanged += Problem_BestKnownQualityParameter_Value_ValueChanged;
UpdateTargetValueFromBestKnownQuality();
}
}
private void Problem_BestKnownQualityParameter_Value_ValueChanged(object sender, EventArgs e) {
UpdateTargetValueFromBestKnownQuality();
}
protected override void Problem_Reset(object sender, EventArgs eventArgs) {
if (Algorithm != null) AddAlgorithmAnalyzers();
}
protected override void Problem_OperatorsChanged(object sender, EventArgs eventArgs) {
if (Algorithm != null) AddAlgorithmAnalyzers();
}
protected override void OnProblemChanged() {
base.OnProblemChanged();
if (Algorithm != null) Algorithm.Problem = Problem;
if (Problem != null) UpdateTargetValueFromBestKnownQuality();
}
private void MaximumEvaluationsParameterOnValueChanged(object sender, EventArgs eventArgs) {
SynchronizeMaximumEvaluationsParameter();
}
private void TargetQualityParameterChanged(object sender, EventArgs e) {
if (TargetQualityParameter.Value != null) TargetQualityParameter.Value.ValueChanged += TargetQualityParameterOnValueChanged;
HandleAlgorithmTargetQualityChanged();
}
private void TargetQualityParameterOnValueChanged(object sender, EventArgs eventArgs) {
HandleAlgorithmTargetQualityChanged();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
System.Timers.Timer timer = (System.Timers.Timer)sender;
timer.Enabled = false;
DateTime now = DateTime.UtcNow;
ExecutionTime += now - lastUpdateTime;
lastUpdateTime = now;
timer.Enabled = true;
}
#endregion
private void HandleAlgorithmTargetQualityChanged() {
if (Algorithm == null) return;
IParameter param;
if (!Algorithm.Parameters.TryGetValue("TargetQuality", out param)) return;
var doubleValueParam = (param as IValueParameter);
if (doubleValueParam == null) return;
if (doubleValueParam.Value == null && TargetQualityParameter.Value != null) {
doubleValueParam.Value = new DoubleValue(TargetQualityParameter.Value.Value);
} else if (doubleValueParam.Value != null && TargetQualityParameter.Value == null) {
doubleValueParam.Value = null;
} else if (doubleValueParam.Value != null && TargetQualityParameter.Value != null) {
doubleValueParam.Value.Value = TargetQualityParameter.Value.Value;
}
}
private void HandleAlgorithmMaximumEvaluationsChanged() {
if (Algorithm == null) return;
IParameter param;
if (!Algorithm.Parameters.TryGetValue("MaximumEvaluations", out param)) return;
var intValueParam = (param as IValueParameter);
if (intValueParam == null) return;
var value = intValueParam.Value;
if (value.Value > MaximumEvaluationsParameter.Value.Value)
value.Value = MaximumEvaluationsParameter.Value.Value;
}
private void SynchronizeMaximumEvaluationsParameter() {
if (Algorithm == null) return;
IParameter param;
if (!Algorithm.Parameters.TryGetValue("MaximumEvaluations", out param)) return;
var intValueParam = (param as IValueParameter);
if (intValueParam == null) return;
if (intValueParam.Value == null) intValueParam.Value = new IntValue(MaximumEvaluationsParameter.Value.Value);
else intValueParam.Value.Value = MaximumEvaluationsParameter.Value.Value;
}
}
}