#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; } } }