Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
08/13/15 14:19:29 (9 years ago)
Author:
abeham
Message:

#2431: Added AlgorithmIterator instead of IRRestarter

  • AlgorithmIterator implements IAlgorithm whereas IRRestarter implemented only IOptimizer
  • Deriving from Algorithm leads to better design
File:
1 copied

Legend:

Unmodified
Added
Removed
  • branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/AlgorithmIterator.cs

    r12839 r12856  
    2121
    2222using System;
    23 using System.Collections.Generic;
    24 using System.ComponentModel;
    25 using System.Drawing;
    2623using System.Linq;
     24using System.Threading;
    2725using HeuristicLab.Common;
    28 using HeuristicLab.Common.Resources;
    2926using HeuristicLab.Core;
    3027using HeuristicLab.Data;
    3128using HeuristicLab.Optimization;
     29using HeuristicLab.Parameters;
    3230using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     31using System.Threading.Tasks;
    3332
    3433namespace HeuristicLab.Analysis {
    35   public enum TerminationCriterium { OnlyByTime, OnlyByEvaluations, OnlyByTarget, ByTargetAndTime, ByTargetAndEvaluations, ByTimeAndEvaluations, WhicheverHitsFirst, WhicheverHitsLast }
    3634  /// <summary>
    3735  /// A run in which an algorithm is executed for a certain maximum time only.
    3836  /// </summary>
    39   [Item("Independent Random Restarter", "An optimizer that repeats an algorithm until either a certain target value is reached or a maximum budget is exceeded.")]
    40   [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 117)]
     37  [Item("Algorithm Iterator", "An algorithm that repeats an algorithm until either a certain target value is reached or a maximum budget is exceeded.")]
     38  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 116)]
    4139  [StorableClass]
    42   public sealed class IndepdentRandomRestarter : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
     40  public sealed class AlgorithmIterator : Algorithm, IStorableContent {
    4341    private const string ExecutionTimeResultName = "Execution Time";
    4442    private const string BestQualityResultName = "BestQuality";
     
    4846    private const string QualityPerClockResultName = "QualityPerClock";
    4947    private const string QualityPerEvaluationsResultName = "QualityPerEvaluations";
     48    private const string EvaluationsResultName = "Evaluations";
    5049
    5150    public string Filename { get; set; }
    5251
    53     #region ItemImage
    54     public static new Image StaticItemImage {
    55       get { return VSImageLibrary.Event; }
    56     }
    57     public override Image ItemImage {
    58       get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
    59     }
    60     #endregion
     52    public override Type ProblemType { get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); } }
     53    public new ISingleObjectiveHeuristicOptimizationProblem Problem {
     54      get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
     55      set {
     56        base.Problem = value;
     57        if (Algorithm != null) Algorithm.Problem = Problem;
     58        if (Problem != null) UpdateTargetValueFromBestKnownQuality();
     59      }
     60    }
     61
     62    public IValueParameter<TimeSpanValue> MaximumExecutionTimeParameter {
     63      get { return (IValueParameter<TimeSpanValue>)Parameters["MaximumExecutionTime"]; }
     64    }
     65
     66    public IValueParameter<IntValue> MaximumEvaluationsParameter {
     67      get { return (IValueParameter<IntValue>)Parameters["MaximumEvaluations"]; }
     68    }
     69
     70    public IValueParameter<DoubleValue> TargetValueParameter {
     71      get { return (IValueParameter<DoubleValue>)Parameters["TargetValue"]; }
     72    }
     73
     74    private IFixedValueParameter<DoubleValue> MoveCostPerSolutionParameter {
     75      get { return (IFixedValueParameter<DoubleValue>)Parameters["MoveCostPerSolution"]; }
     76    }
     77
     78    private IFixedValueParameter<BoolValue> StoreSolutionInRunParameter {
     79      get { return (IFixedValueParameter<BoolValue>)Parameters["StoreSolutionInRun"]; }
     80    }
     81
     82    private IValueParameter<IAlgorithm> AlgorithmParameter {
     83      get { return (IValueParameter<IAlgorithm>)Parameters["Algorithm"]; }
     84    }
    6185
    6286    [Storable]
    63     private TerminationCriterium terminationCriterium;
    64     public TerminationCriterium TerminationCriterium {
    65       get { return terminationCriterium; }
    66       set {
    67         if (terminationCriterium == value) return;
    68         terminationCriterium = value;
    69         OnPropertyChanged("TerminationCriterium");
    70       }
    71     }
    72 
    73     [Storable]
    74     private TimeSpan maximumExecutionTime;
    75     public TimeSpan MaximumExecutionTime {
    76       get { return maximumExecutionTime; }
    77       set {
    78         if (maximumExecutionTime == value) return;
    79         maximumExecutionTime = value;
    80         OnPropertyChanged("MaximumExecutionTime");
    81       }
    82     }
    83 
    84     [Storable]
    85     private int maximumEvaluations;
    86     public int MaximumEvaluations {
    87       get { return maximumEvaluations; }
    88       set {
    89         if (maximumEvaluations == value) return;
    90         maximumEvaluations = value;
    91         OnPropertyChanged("MaximumEvaluations");
    92       }
    93     }
    94 
    95     [Storable]
    96     private double targetValue;
    97     public double TargetValue {
    98       get { return targetValue; }
    99       set {
    100         if (targetValue == value) return;
    101         targetValue = value;
    102         OnPropertyChanged("TargetValue");
    103       }
    104     }
    105 
    106     [Storable]
    107     private bool maximization;
    108     public bool Maximization {
    109       get { return maximization; }
    110       set {
    111         if (maximization == value) return;
    112         maximization = value;
    113         OnPropertyChanged("Maximization");
    114       }
    115     }
    116 
    117     [Storable]
    118     private double moveCostPerSolution;
    119     public double MoveCostPerSolution {
    120       get { return moveCostPerSolution; }
    121       set {
    122         if (moveCostPerSolution == value) return;
    123         moveCostPerSolution = value;
    124         perEvaluationsAnalyzer.MoveCostPerSolutionParameter.Value = new DoubleValue(moveCostPerSolution);
    125         OnPropertyChanged("MoveCostPerSolution");
    126       }
    127     }
    128 
    129     [Storable]
    130     private bool storeSolutionInRun;
    131     public bool StoreSolutionInRun {
    132       get { return storeSolutionInRun; }
    133       set {
    134         if (storeSolutionInRun == value) return;
    135         storeSolutionInRun = value;
    136         OnPropertyChanged("StoreSolutionInRun");
    137       }
     87    private ResultCollection results;
     88    public override ResultCollection Results {
     89      get { return results; }
    13890    }
    13991
     
    14395    private QualityPerEvaluationsAnalyzer perEvaluationsAnalyzer;
    14496
    145     [Storable]
    146     private ExecutionState executionState;
    147     public ExecutionState ExecutionState {
    148       get { return executionState; }
    149       private set {
    150         if (executionState != value) {
    151           executionState = value;
    152           OnExecutionStateChanged();
    153           OnItemImageChanged();
    154         }
    155       }
    156     }
    157 
    158     private TimeSpan lastAlgorithmExecutionTime;
    159     [Storable]
    160     private TimeSpan executionTime;
    161     public TimeSpan ExecutionTime {
    162       get { return executionTime; }
    163       set {
    164         if (executionTime == value) return;
    165         executionTime = value;
    166         OnPropertyChanged("ExecutionTime");
    167         OnExecutionTimeChanged();
    168       }
    169     }
    170 
    171     [Storable]
    172     private double evaluations;
    173     public double Evaluations {
    174       get { return evaluations; }
    175       set {
    176         if (evaluations == value) return;
    177         evaluations = value;
    178         OnPropertyChanged("Evaluations");
    179       }
    180     }
    181 
    182     [Storable]
    183     private double bestSoFar;
    184     public double BestSoFar {
    185       get { return bestSoFar; }
    186       set {
    187         if (bestSoFar == value) return;
    188         bestSoFar = value;
    189         OnPropertyChanged("BestSoFar");
    190       }
    191     }
    192 
    193     [Storable]
    194     private IRun currentRun;
    195     public IRun CurrentRun {
    196       get { return currentRun; }
    197       private set {
    198         if (currentRun == value) return;
    199         currentRun = value;
    200         OnPropertyChanged("CurrentRun");
    201       }
     97    public double MoveCostPerSolution {
     98      get { return MoveCostPerSolutionParameter.Value.Value; }
     99      set { MoveCostPerSolutionParameter.Value.Value = value; }
     100    }
     101
     102    public bool StoreSolutionInRun {
     103      get { return StoreSolutionInRunParameter.Value.Value; }
     104      set { StoreSolutionInRunParameter.Value.Value = value; }
    202105    }
    203106
     
    214117        algorithm = value;
    215118        if (algorithm != null) {
     119          if (algorithm.ExecutionState != ExecutionState.Prepared)
     120            algorithm.Prepare(true);
     121          algorithm.Problem = Problem;
    216122          RegisterAlgorithmEvents();
    217123          AddAlgorithmAnalyzers();
    218124        }
    219         OnPropertyChanged("Algorithm");
     125        if (AlgorithmParameter.Value != algorithm)
     126          AlgorithmParameter.Value = algorithm;
    220127        Prepare();
    221128      }
    222129    }
    223130
    224     [Storable]
    225     private RunCollection runs;
    226     public RunCollection Runs {
    227       get { return runs; }
    228       private set {
    229         if (value == null) throw new ArgumentNullException();
    230         if (runs == value) return;
    231         runs = value;
    232         OnPropertyChanged("Runs");
    233       }
    234     }
    235 
    236     public IEnumerable<IOptimizer> NestedOptimizers {
    237       get {
    238         if (Algorithm == null) yield break;
    239         yield return Algorithm;
    240         foreach (var opt in Algorithm.NestedOptimizers)
    241           yield return opt;
    242       }
     131    private bool Maximization {
     132      get { return Problem != null && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value; }
    243133    }
    244134
    245135    private bool IsFinished {
    246136      get {
    247         var timeHit = ExecutionTime >= MaximumExecutionTime;
    248         var evalHit = Evaluations >= MaximumEvaluations;
    249         var targetHit = (Maximization && BestSoFar >= TargetValue || !Maximization && BestSoFar <= TargetValue);
    250 
    251         return timeHit && evalHit && targetHit
    252           || timeHit && (TerminationCriterium == TerminationCriterium.OnlyByTime
    253                       || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst
    254                       || TerminationCriterium == TerminationCriterium.ByTargetAndTime
    255                       || TerminationCriterium == TerminationCriterium.ByTimeAndEvaluations)
    256           || evalHit && (TerminationCriterium == TerminationCriterium.OnlyByEvaluations
    257                       || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst
    258                       || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations
    259                       || TerminationCriterium == TerminationCriterium.ByTimeAndEvaluations)
    260           || targetHit && (TerminationCriterium == TerminationCriterium.OnlyByTarget
    261                         || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst
    262                         || TerminationCriterium == TerminationCriterium.ByTargetAndTime
    263                         || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations);
    264       }
    265     }
    266 
    267     private ISingleObjectiveHeuristicOptimizationProblem problem;
     137        var executionTime = Results.ContainsKey(ExecutionTimeResultName) ? ((TimeSpanValue)Results[ExecutionTimeResultName].Value).Value : TimeSpan.Zero;
     138        var evaluations = Results.ContainsKey(EvaluationsResultName) ? ((DoubleValue)Results[EvaluationsResultName].Value).Value : 0;
     139        var bestQuality = Results.ContainsKey(BestQualityResultName) ? ((DoubleValue)Results[BestQualityResultName].Value).Value
     140                                                                     : (Maximization ? double.MinValue : double.MaxValue);
     141        var targetValue = TargetValueParameter.Value != null ? TargetValueParameter.Value.Value
     142                                                             : Maximization ? double.MaxValue : double.MinValue;
     143
     144        var timeHit = MaximumExecutionTimeParameter.Value != null && executionTime >= MaximumExecutionTimeParameter.Value.Value;
     145        var evalHit = MaximumEvaluationsParameter.Value != null && evaluations >= MaximumEvaluationsParameter.Value.Value;
     146        var targetHit = Maximization && bestQuality >= targetValue || !Maximization && bestQuality <= targetValue;
     147
     148        return timeHit || evalHit || targetHit;
     149      }
     150    }
    268151
    269152    [StorableConstructor]
    270     private IndepdentRandomRestarter(bool deserializing) : base(deserializing) { }
    271     private IndepdentRandomRestarter(IndepdentRandomRestarter original, Cloner cloner)
     153    private AlgorithmIterator(bool deserializing) : base(deserializing) { }
     154    private AlgorithmIterator(AlgorithmIterator original, Cloner cloner)
    272155      : base(original, cloner) {
    273       terminationCriterium = original.terminationCriterium;
    274       maximumExecutionTime = original.maximumExecutionTime;
    275       maximumEvaluations = original.maximumEvaluations;
    276       moveCostPerSolution = original.moveCostPerSolution;
    277       storeSolutionInRun = original.storeSolutionInRun;
    278       targetValue = original.targetValue;
    279       maximization = original.maximization;
    280       executionTime = original.executionTime;
    281       evaluations = original.evaluations;
    282       bestSoFar = original.bestSoFar;
    283       lastAlgorithmExecutionTime = original.lastAlgorithmExecutionTime;
    284 
     156      results = cloner.Clone(original.Results);
    285157      perClockAnalyzer = cloner.Clone(original.perClockAnalyzer);
    286158      perEvaluationsAnalyzer = cloner.Clone(original.perEvaluationsAnalyzer);
    287159
    288       algorithm = cloner.Clone(original.algorithm);
    289       runs = cloner.Clone(original.runs);
    290 
    291       ExecutionState = original.ExecutionState;
    292 
    293       Initialize();
    294     }
    295     public IndepdentRandomRestarter()
     160      RegisterEventHandlers();
     161    }
     162    public AlgorithmIterator()
    296163      : base() {
    297       name = ItemName;
    298       description = ItemDescription;
    299       terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
    300       maximumExecutionTime = TimeSpan.FromMinutes(1);
    301       maximumEvaluations = 10000000; // 10 mio
    302       moveCostPerSolution = 1;
    303       storeSolutionInRun = false;
    304       targetValue = 0;
    305       maximization = false;
    306       executionTime = TimeSpan.Zero;
    307       evaluations = 0;
    308       bestSoFar = double.NaN;
    309       lastAlgorithmExecutionTime = TimeSpan.Zero;
     164      results = new ResultCollection();
     165      Parameters.Add(new OptionalValueParameter<TimeSpanValue>("MaximumExecutionTime", "The maximum wall-clock time that the algorithm should run."));
     166      Parameters.Add(new OptionalValueParameter<IntValue>("MaximumEvaluations", "The maximum number of function evaluations that the algorithm should run.", new IntValue(100000000)));
     167      Parameters.Add(new OptionalValueParameter<DoubleValue>("TargetValue", "The target value that the algorithm should run for."));
     168      Parameters.Add(new FixedValueParameter<DoubleValue>("MoveCostPerSolution", "The amount of solution evaluation equivalents of a single move. Use 1 for a black-box scenario.", new DoubleValue(1)));
     169      Parameters.Add(new FixedValueParameter<BoolValue>("StoreSolutionInRun", "Whether the solution data types should be kept in the run."));
     170      Parameters.Add(new ValueParameter<IAlgorithm>("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
    310171
    311172      perClockAnalyzer = new QualityPerClockAnalyzer();
    312173      perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
    313174
    314       Runs = new RunCollection { OptimizerName = Name };
    315       Initialize();
    316     }
    317     public IndepdentRandomRestarter(string name)
    318       : base(name) {
    319       description = ItemDescription;
    320       terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
    321       maximumExecutionTime = TimeSpan.FromMinutes(1);
    322       maximumEvaluations = 10000000; // 10 mio
    323       moveCostPerSolution = 1;
    324       storeSolutionInRun = false;
    325       targetValue = 0;
    326       maximization = false;
    327       executionTime = TimeSpan.Zero;
    328       evaluations = 0;
    329       bestSoFar = double.NaN;
    330       lastAlgorithmExecutionTime = TimeSpan.Zero;
    331 
    332       perClockAnalyzer = new QualityPerClockAnalyzer();
    333       perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
    334 
    335       Runs = new RunCollection { OptimizerName = Name };
    336       Initialize();
    337     }
    338     public IndepdentRandomRestarter(string name, string description)
    339       : base(name, description) {
    340       terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
    341       maximumExecutionTime = TimeSpan.FromMinutes(1);
    342       maximumEvaluations = 10000000; // 10 mio
    343       moveCostPerSolution = 1;
    344       storeSolutionInRun = false;
    345       targetValue = 0;
    346       maximization = false;
    347       executionTime = TimeSpan.Zero;
    348       evaluations = 0;
    349       bestSoFar = double.NaN;
    350       lastAlgorithmExecutionTime = TimeSpan.Zero;
    351 
    352       perClockAnalyzer = new QualityPerClockAnalyzer();
    353       perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
    354 
    355       Runs = new RunCollection { OptimizerName = Name };
    356       Initialize();
     175      RegisterEventHandlers();
    357176    }
    358177
    359178    public override IDeepCloneable Clone(Cloner cloner) {
    360179      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
    361       return new IndepdentRandomRestarter(this, cloner);
     180      return new AlgorithmIterator(this, cloner);
    362181    }
    363182
    364183    [StorableHook(HookType.AfterDeserialization)]
    365184    private void AfterDeserialization() {
    366       Initialize();
    367     }
    368 
    369     private void Initialize() {
    370       if (algorithm != null) RegisterAlgorithmEvents();
    371     }
    372 
    373     private void Reset() {
    374       ExecutionTime = TimeSpan.Zero;
    375       Evaluations = 0;
    376       BestSoFar = double.NaN;
    377       lastAlgorithmExecutionTime = TimeSpan.Zero;
    378 
    379       CurrentRun = null;
    380     }
    381 
    382     public void Prepare() {
    383       Prepare(false);
    384     }
    385     public void Prepare(bool clearRuns) {
    386       if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
    387         throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
    388       Reset();
    389 
    390       if (Algorithm != null) {
    391         Algorithm.Prepare(clearRuns);
    392         ExecutionState = ExecutionState.Prepared;
    393         OnPrepared();
    394       }
    395     }
    396     public void Start() {
    397       if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
    398         throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
    399 
    400       if (ExecutionState == ExecutionState.Prepared) {
    401         CurrentRun = new Run(Algorithm) {
    402           Name = Algorithm.Name + " IRRRun" + Runs.Count
    403         };
    404         if (!CurrentRun.Results.ContainsKey(ExecutionTimeResultName))
    405           CurrentRun.Results.Add(ExecutionTimeResultName, new TimeSpanValue(TimeSpan.Zero));
    406         // use double instead of int, otherwise one might run into int.MaxValue (at least with moves)
    407         CurrentRun.Results.Add(EvaluatedSolutionsResultName, new DoubleValue(0));
    408         CurrentRun.Results.Add(EvaluatedMovesResultName, new DoubleValue(0));
    409         CurrentRun.Results.Add(BestQualityResultName, new DoubleValue(Maximization ? double.MinValue : double.MaxValue));
    410         CurrentRun.Results.Add(RandomRestartsResultName, new IntValue(0));
    411       }
    412       if (Algorithm.ExecutionState == ExecutionState.Stopped)
     185      RegisterEventHandlers();
     186    }
     187
     188    #region Register Event Handlers
     189    protected override void RegisterProblemEvents() {
     190      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
     191      if (bkParam != null) {
     192        bkParam.ValueChanged += Problem_BestKnownQualityParameter_ValueChanged;
     193      }
     194      base.RegisterProblemEvents();
     195    }
     196    protected override void DeregisterProblemEvents() {
     197      base.DeregisterProblemEvents();
     198      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
     199      if (bkParam != null) {
     200        bkParam.ValueChanged -= Problem_BestKnownQualityParameter_ValueChanged;
     201      }
     202    }
     203    private void RegisterAlgorithmEvents() {
     204      Algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
     205      Algorithm.Paused += Algorithm_Paused;
     206      Algorithm.Stopped += Algorithm_Stopped;
     207      Algorithm.ProblemChanged += Algorithm_ProblemChanged;
     208    }
     209    private void DeregisterAlgorithmEvents() {
     210      Algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
     211      Algorithm.Paused -= Algorithm_Paused;
     212      Algorithm.Stopped -= Algorithm_Stopped;
     213      Algorithm.ProblemChanged -= Algorithm_ProblemChanged;
     214    }
     215    #endregion
     216
     217    private void RegisterEventHandlers() {
     218      if (Algorithm != null) RegisterAlgorithmEvents();
     219      if (Problem != null) RegisterProblemEvents();
     220      AlgorithmParameter.ValueChanged += AlgorithmParameterOnValueChanged;
     221    }
     222
     223    private void AlgorithmParameterOnValueChanged(object sender, EventArgs eventArgs) {
     224      Algorithm = AlgorithmParameter.Value;
     225    }
     226
     227    #region Prepare, Start, Pause, Stop
     228    public override void Prepare() {
     229      if (Problem == null || Algorithm == null) return;
     230
     231      Algorithm.Prepare(true);
     232
     233      results.Clear();
     234      OnPrepared();
     235    }
     236
     237    public override void Start() {
     238      base.Start();
     239      OnStarted();
     240      var task = Task.Factory.StartNew(Run, null);
     241      task.ContinueWith(t => {
     242        try {
     243          t.Wait();
     244        } catch (AggregateException ex) {
     245          try {
     246            ex.Flatten().Handle(x => x is OperationCanceledException);
     247          } catch (AggregateException remaining) {
     248            if (remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
     249            else OnExceptionOccurred(remaining);
     250          }
     251        }
     252        if (Algorithm.ExecutionState == ExecutionState.Paused) OnPaused();
     253        else OnStopped();
     254      });
     255    }
     256
     257    public override void Pause() {
     258      base.Pause();
     259      Algorithm.Pause();
     260    }
     261
     262    public override void Stop() {
     263      base.Stop();
     264      Algorithm.Stop();
     265    }
     266    #endregion
     267
     268    private DateTime lastUpdateTime;
     269    private void Run(object state) {
     270      lastUpdateTime = DateTime.UtcNow;
     271      System.Timers.Timer timer = new System.Timers.Timer(250);
     272      timer.AutoReset = true;
     273      timer.Elapsed += timer_Elapsed;
     274      timer.Start();
     275      try {
     276        Run();
     277      } finally {
     278        timer.Elapsed -= timer_Elapsed;
     279        timer.Stop();
     280        ExecutionTime += DateTime.UtcNow - lastUpdateTime;
     281      }
     282    }
     283
     284    private readonly AutoResetEvent algorithmWaitHandle = new AutoResetEvent(false);
     285    private void Run() {
     286      if (!Results.ContainsKey(ExecutionTimeResultName)) Results.Add(new Result(ExecutionTimeResultName, new TimeSpanValue(TimeSpan.Zero)));
     287      if (!Results.ContainsKey(EvaluatedSolutionsResultName)) Results.Add(new Result(EvaluatedSolutionsResultName, new DoubleValue(0)));
     288      if (!Results.ContainsKey(EvaluatedMovesResultName)) Results.Add(new Result(EvaluatedMovesResultName, new DoubleValue(0)));
     289      if (!Results.ContainsKey(EvaluationsResultName)) Results.Add(new Result(EvaluationsResultName, new DoubleValue(0)));
     290      if (!Results.ContainsKey(BestQualityResultName)) Results.Add(new Result(BestQualityResultName, new DoubleValue(double.NaN)));
     291
     292      do {
     293        if (!Results.ContainsKey(RandomRestartsResultName)) Results.Add(new Result(RandomRestartsResultName, new IntValue(0)));
     294        else if (Algorithm.ExecutionState == ExecutionState.Prepared) ((IntValue)Results[RandomRestartsResultName].Value).Value++;
     295
     296        Algorithm.Start();
     297        algorithmWaitHandle.WaitOne();
     298
     299        if (Algorithm.ExecutionState == ExecutionState.Paused) return;
     300
     301        var execTime = ((TimeSpanValue)Results[ExecutionTimeResultName].Value);
     302        var solEvals = ((DoubleValue)Results[EvaluatedSolutionsResultName].Value);
     303        var movEvals = ((DoubleValue)Results[EvaluatedMovesResultName].Value);
     304        var restarts = ((IntValue)Results[RandomRestartsResultName].Value);
     305        var evaluations = ((DoubleValue)Results[EvaluationsResultName].Value);
     306        var bestQuality = ((DoubleValue)Results[BestQualityResultName].Value);
     307        var improvement = false;
     308
     309        IResult result;
     310        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out result)) {
     311          var evals = ((IntValue)result.Value).Value;
     312          evaluations.Value += evals;
     313          solEvals.Value += evals;
     314        }
     315        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out result)) {
     316          var evals = ((IntValue)result.Value).Value;
     317          evaluations.Value += MoveCostPerSolution * evals;
     318          movEvals.Value += evals;
     319        }
     320        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out result)) {
     321          var newBestQuality = ((DoubleValue)result.Value).Value;
     322          if (double.IsNaN(bestQuality.Value)
     323              || Maximization && newBestQuality > bestQuality.Value
     324              || !Maximization && newBestQuality < bestQuality.Value) {
     325            bestQuality.Value = newBestQuality;
     326            improvement = true;
     327          }
     328        }
     329        if (Algorithm.Results.TryGetValue(perClockAnalyzer.QualityPerClockParameter.ResultName, out result)) {
     330          UpdateQualityPerClockResult((IndexedDataTable<double>)result.Value, restarts.Value);
     331        }
     332        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ResultName, out result)) {
     333          UpdateQualityPerEvaluationsResult((IndexedDataTable<double>)result.Value, restarts.Value);
     334        }
     335        if (StoreSolutionInRun) {
     336          foreach (var r in Algorithm.Results) {
     337            if (r.Name.ToLower().EndsWith("solution") && improvement) {
     338              if (!Results.TryGetValue(r.Name, out result))
     339                Results.Add(new Result(r.Name, (IItem)r.Value.Clone()));
     340              else result.Value = (IItem)r.Value.Clone();
     341            }
     342          }
     343        }
     344
     345        execTime.Value = ExecutionTime;
     346
    413347        Algorithm.Prepare(true);
    414       Algorithm.Start();
    415       ExecutionState = ExecutionState.Started;
    416       OnStarted();
    417     }
    418     public void Pause() {
    419       if (ExecutionState != ExecutionState.Started)
    420         throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
    421       Algorithm.Pause();
    422       ExecutionState = ExecutionState.Paused;
    423       OnPaused();
    424     }
    425 
    426     private bool forceStop = false;
    427     public void Stop() {
    428       if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
    429         throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
    430       forceStop = true;
    431       try {
    432         Algorithm.Stop();
    433       } catch (InvalidOperationException) {
    434         // sometimes we hit the algorithm in an invalid state
    435       }
    436     }
    437 
    438     private void AddAlgorithmAnalyzers() {
    439       if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
    440       var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
    441       if (analyzerParam == null) return;
    442       if (!analyzerParam.Value.Operators.Contains(perClockAnalyzer))
    443         analyzerParam.Value.Operators.Add(perClockAnalyzer);
    444       if (!analyzerParam.Value.Operators.Contains(perEvaluationsAnalyzer))
    445         analyzerParam.Value.Operators.Add(perEvaluationsAnalyzer);
    446     }
    447 
    448     private void RemoveAlgorithmAnalyzers() {
    449       if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
    450       var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
    451       if (analyzerParam == null) return;
    452       analyzerParam.Value.Operators.Remove(perClockAnalyzer);
    453       analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
    454     }
    455 
    456     #region Events
    457     protected override void OnNameChanged() {
    458       base.OnNameChanged();
    459       runs.OptimizerName = Name;
    460     }
    461 
    462     public event PropertyChangedEventHandler PropertyChanged;
    463     private void OnPropertyChanged(string property) {
    464       var handler = PropertyChanged;
    465       if (handler != null) handler(this, new PropertyChangedEventArgs(property));
    466     }
    467 
    468     #region IExecutable Events
    469     public event EventHandler ExecutionStateChanged;
    470     private void OnExecutionStateChanged() {
    471       var handler = ExecutionStateChanged;
    472       if (handler != null) handler(this, EventArgs.Empty);
    473     }
    474     public event EventHandler ExecutionTimeChanged;
    475     private void OnExecutionTimeChanged() {
    476       var handler = ExecutionTimeChanged;
    477       if (handler != null) handler(this, EventArgs.Empty);
    478     }
    479     public event EventHandler Prepared;
    480     private void OnPrepared() {
    481       var handler = Prepared;
    482       if (handler != null) handler(this, EventArgs.Empty);
    483     }
    484     public event EventHandler Started;
    485     private void OnStarted() {
    486       var handler = Started;
    487       if (handler != null) handler(this, EventArgs.Empty);
    488     }
    489     public event EventHandler Paused;
    490     private void OnPaused() {
    491       var handler = Paused;
    492       if (handler != null) handler(this, EventArgs.Empty);
    493     }
    494     public event EventHandler Stopped;
    495     private void OnStopped() {
    496       var handler = Stopped;
    497       if (handler != null) handler(this, EventArgs.Empty);
    498     }
    499     public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
    500     private void OnExceptionOccurred(Exception exception) {
    501       var handler = ExceptionOccurred;
    502       if (handler != null) handler(this, new EventArgs<Exception>(exception));
    503     }
    504     #endregion
    505 
    506     #region Algorithm Events
    507     private void RegisterAlgorithmEvents() {
    508       algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
    509       algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
    510       algorithm.Paused += Algorithm_Paused;
    511       algorithm.Prepared += Algorithm_Prepared;
    512       algorithm.Stopped += Algorithm_Stopped;
    513       algorithm.ProblemChanged += Algorithm_ProblemChanged;
    514       Algorithm_ProblemChanged(algorithm, EventArgs.Empty);
    515     }
    516     private void DeregisterAlgorithmEvents() {
    517       algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
    518       algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
    519       algorithm.Paused -= Algorithm_Paused;
    520       algorithm.Prepared -= Algorithm_Prepared;
    521       algorithm.Stopped -= Algorithm_Stopped;
    522       algorithm.ProblemChanged -= Algorithm_ProblemChanged;
    523     }
    524     private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
    525       OnExceptionOccurred(e.Value);
    526     }
    527     private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
    528       ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
    529       lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
    530     }
    531     private void Algorithm_Paused(object sender, EventArgs e) {
    532       ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
    533       lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
    534       OnPaused();
    535     }
    536     private void Algorithm_Prepared(object sender, EventArgs e) {
    537       lastAlgorithmExecutionTime = TimeSpan.Zero;
    538     }
    539     private void Algorithm_Stopped(object sender, EventArgs e) {
    540       ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
    541       lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
    542 
    543       var execTime = ((TimeSpanValue)CurrentRun.Results[ExecutionTimeResultName]).Value;
    544       var solEvals = ((DoubleValue)CurrentRun.Results[EvaluatedSolutionsResultName]).Value;
    545       var movEvals = ((DoubleValue)CurrentRun.Results[EvaluatedMovesResultName]).Value;
    546       var restarts = ((IntValue)CurrentRun.Results[RandomRestartsResultName]).Value;
    547       var improvement = false;
    548 
    549       IResult result;
    550       if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out result)) {
    551         var evals = ((IntValue)result.Value).Value;
    552         Evaluations += evals;
    553         CurrentRun.Results[EvaluatedSolutionsResultName] = new DoubleValue(solEvals + evals);
    554       }
    555       if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out result)) {
    556         var evals = ((IntValue)result.Value).Value;
    557         Evaluations += moveCostPerSolution * evals;
    558         CurrentRun.Results[EvaluatedMovesResultName] = new DoubleValue(movEvals + evals);
    559       }
    560       if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out result)) {
    561         var bestQuality = ((DoubleValue)result.Value).Value;
    562         if (double.IsNaN(BestSoFar)
    563             || Maximization && bestQuality > BestSoFar
    564             || !Maximization && bestQuality < BestSoFar) {
    565           BestSoFar = bestQuality;
    566           CurrentRun.Results[BestQualityResultName] = new DoubleValue(bestQuality);
    567           improvement = true;
    568         }
    569       }
    570       if (Algorithm.Results.TryGetValue(perClockAnalyzer.QualityPerClockParameter.ResultName, out result)) {
    571         UpdateQualityPerClockResult((IndexedDataTable<double>)result.Value, execTime, restarts);
    572       }
    573       if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ResultName, out result)) {
    574         UpdateQualityPerEvaluationsResult((IndexedDataTable<double>)result.Value, solEvals, movEvals, restarts);
    575       }
    576       if (StoreSolutionInRun) {
    577         foreach (var r in Algorithm.Results) {
    578           if (r.Name.ToLower().EndsWith("solution") && improvement) {
    579             CurrentRun.Results[r.Name] = (IItem)r.Value.Clone();
    580           }
    581         }
    582       }
    583 
    584       CurrentRun.Results[ExecutionTimeResultName] = new TimeSpanValue(execTime + Algorithm.ExecutionTime);
    585 
    586       // Algorithm sets ExecutionTime to zero before firing Prepared
    587       // We will thus see ExecutionTimeChanged before Prepared
    588       lastAlgorithmExecutionTime = TimeSpan.Zero;
    589 
    590       if (!forceStop && !IsFinished) {
    591         CurrentRun.Results[RandomRestartsResultName] = new IntValue(restarts + 1);
    592         Algorithm.Prepare(true);
    593         Algorithm.Start();
    594       } else {
    595         forceStop = false;
    596         Runs.Add(CurrentRun);
    597         Algorithm.Prepare(true);
    598         ExecutionState = ExecutionState.Stopped;
    599         OnStopped();
    600       }
    601     }
    602 
    603     private void UpdateQualityPerClockResult(IndexedDataTable<double> perClock, TimeSpan execTime, int restarts) {
     348      } while (!IsFinished);
     349    }
     350
     351    private void UpdateQualityPerClockResult(IndexedDataTable<double> perClock, int restarts) {
    604352      IndexedDataTable<double> dt;
    605       if (!CurrentRun.Results.ContainsKey(QualityPerClockResultName)) {
     353      if (!Results.ContainsKey(QualityPerClockResultName)) {
    606354        dt = (IndexedDataTable<double>)perClock.Clone();
    607355        if (!dt.Rows.ContainsKey("Restarts"))
     
    614362        foreach (var v in dt.Rows.First().Values)
    615363          dt.Rows["Restarts"].Values.Add(Tuple.Create(v.Item1, 0.0));
    616         CurrentRun.Results.Add(QualityPerClockResultName, dt);
     364        Results.Add(new Result(QualityPerClockResultName, dt));
    617365      } else {
    618         dt = (IndexedDataTable<double>)CurrentRun.Results[QualityPerClockResultName];
    619         var best = dt.Rows.First().Values.Last().Item2;
     366        dt = (IndexedDataTable<double>)Results[QualityPerClockResultName].Value;
     367        var qualityValues = dt.Rows.First().Values;
     368        var restartValues = dt.Rows["Restarts"].Values;
     369        var best = qualityValues.Last().Item2;
     370        var execTime = qualityValues.Last().Item1;
     371        var improvement = false;
    620372        foreach (var tupl in perClock.Rows.First().Values) {
    621373          if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
    622             dt.Rows.First().Values.Add(Tuple.Create(execTime.TotalSeconds + tupl.Item1, tupl.Item2));
    623             dt.Rows["Restarts"].Values.Add(Tuple.Create(execTime.TotalSeconds + tupl.Item1, (double)restarts));
     374            if (!improvement) {
     375              // the last entry always holds the same value, but with highest execution time
     376              qualityValues.RemoveAt(qualityValues.Count - 1);
     377              restartValues.RemoveAt(restartValues.Count - 1);
     378              improvement = true;
     379            }
     380            qualityValues.Add(Tuple.Create(execTime + tupl.Item1, tupl.Item2));
     381            restartValues.Add(Tuple.Create(execTime + tupl.Item1, (double)restarts));
    624382            best = tupl.Item2;
    625383          }
    626384        }
    627       }
    628       if (IsFinished) {
    629         dt.Rows.First().Values.Add(Tuple.Create(ExecutionTime.TotalSeconds, BestSoFar));
    630         dt.Rows["Restarts"].Values.Add(Tuple.Create(ExecutionTime.TotalSeconds, (double)restarts));
    631       }
    632     }
    633 
    634     private void UpdateQualityPerEvaluationsResult(IndexedDataTable<double> perEvaluations, double solEvals, double movEvals, int restarts) {
     385        if (improvement) {
     386          var totalExecTime = execTime + perClock.Rows.First().Values.Last().Item1;
     387          qualityValues.Add(Tuple.Create(totalExecTime, best));
     388          restartValues.Add(Tuple.Create(totalExecTime, (double)restarts));
     389        }
     390      }
     391    }
     392
     393    private void UpdateQualityPerEvaluationsResult(IndexedDataTable<double> perEvaluations, int restarts) {
    635394      IndexedDataTable<double> dt;
    636       if (!CurrentRun.Results.ContainsKey(QualityPerEvaluationsResultName)) {
     395      if (!Results.ContainsKey(QualityPerEvaluationsResultName)) {
    637396        dt = (IndexedDataTable<double>)perEvaluations.Clone();
    638397        if (!dt.Rows.ContainsKey("Restarts"))
     
    645404        foreach (var v in dt.Rows.First().Values)
    646405          dt.Rows["Restarts"].Values.Add(Tuple.Create(v.Item1, 0.0));
    647         CurrentRun.Results.Add(QualityPerEvaluationsResultName, dt);
     406        Results.Add(new Result(QualityPerEvaluationsResultName, dt));
    648407      } else {
    649         dt = (IndexedDataTable<double>)CurrentRun.Results[QualityPerEvaluationsResultName];
    650         var best = dt.Rows.First().Values.Last().Item2;
     408        dt = (IndexedDataTable<double>)Results[QualityPerEvaluationsResultName].Value;
     409        var qualityValues = dt.Rows.First().Values;
     410        var restartValues = dt.Rows["Restarts"].Values;
     411        var best = qualityValues.Last().Item2;
     412        var evaluations = qualityValues.Last().Item1;
     413        var improvement = false;
    651414        foreach (var tupl in perEvaluations.Rows.First().Values) {
    652415          if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
    653             dt.Rows.First().Values.Add(Tuple.Create(solEvals + moveCostPerSolution * movEvals + tupl.Item1, tupl.Item2));
    654             dt.Rows["Restarts"].Values.Add(Tuple.Create(solEvals + moveCostPerSolution * movEvals + tupl.Item1, (double)restarts));
     416            if (!improvement) {
     417              // the last entry always holds the same value, but with highest evaluations
     418              qualityValues.RemoveAt(qualityValues.Count - 1);
     419              restartValues.RemoveAt(restartValues.Count - 1);
     420              improvement = true;
     421            }
     422            qualityValues.Add(Tuple.Create(evaluations + tupl.Item1, tupl.Item2));
     423            restartValues.Add(Tuple.Create(evaluations + tupl.Item1, (double)restarts));
    655424            best = tupl.Item2;
    656425          }
    657426        }
    658       }
    659       if (IsFinished) {
    660         dt.Rows.First().Values.Add(Tuple.Create(Evaluations, BestSoFar));
    661         dt.Rows["Restarts"].Values.Add(Tuple.Create(Evaluations, (double)restarts));
    662       }
     427        if (improvement) { // add the best quality again as value with highest evaluations
     428          var totalEvaluations = evaluations + perEvaluations.Rows.First().Values.Last().Item1;
     429          qualityValues.Add(Tuple.Create(totalEvaluations, best));
     430          restartValues.Add(Tuple.Create(totalEvaluations, (double)restarts));
     431        }
     432      }
     433    }
     434
     435    private void UpdateTargetValueFromBestKnownQuality() {
     436      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
     437      if (bkParam != null && bkParam.Value != null)
     438        TargetValueParameter.Value = new DoubleValue(bkParam.Value.Value);
     439      else if (bkParam != null && bkParam.Value == null)
     440        TargetValueParameter.Value = null;
     441    }
     442
     443    private void AddAlgorithmAnalyzers() {
     444      if (Algorithm == null) return;
     445      if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
     446      var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
     447      if (analyzerParam != null) {
     448        foreach (var analyzer in analyzerParam.Value.Operators.OfType<QualityPerClockAnalyzer>().ToList())
     449          analyzerParam.Value.Operators.Remove(analyzer);
     450        analyzerParam.Value.Operators.Add(perClockAnalyzer);
     451        foreach (var analyzer in analyzerParam.Value.Operators.OfType<QualityPerEvaluationsAnalyzer>().ToList())
     452          analyzerParam.Value.Operators.Remove(analyzer);
     453        analyzerParam.Value.Operators.Add(perEvaluationsAnalyzer);
     454      } else {
     455        var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter<IMultiAnalyzer>;
     456        if (analyzerParam2 == null) return;
     457        foreach (var analyzer in analyzerParam2.Value.Operators.OfType<QualityPerClockAnalyzer>().ToList())
     458          analyzerParam2.Value.Operators.Remove(analyzer);
     459        analyzerParam2.Value.Operators.Add(perClockAnalyzer);
     460        foreach (var analyzer in analyzerParam2.Value.Operators.OfType<QualityPerEvaluationsAnalyzer>().ToList())
     461          analyzerParam2.Value.Operators.Remove(analyzer);
     462        analyzerParam2.Value.Operators.Add(perEvaluationsAnalyzer);
     463      }
     464    }
     465
     466    private void RemoveAlgorithmAnalyzers() {
     467      if (Algorithm == null) return;
     468      if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
     469      var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
     470      if (analyzerParam != null) {
     471        analyzerParam.Value.Operators.Remove(perClockAnalyzer);
     472        analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
     473      } else {
     474        var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter<IMultiAnalyzer>;
     475        if (analyzerParam2 != null) {
     476          analyzerParam2.Value.Operators.Remove(perClockAnalyzer);
     477          analyzerParam2.Value.Operators.Remove(perEvaluationsAnalyzer);
     478        }
     479      }
     480    }
     481
     482    #region Event Handlers
     483    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
     484      OnExceptionOccurred(e.Value);
     485    }
     486    private void Algorithm_Paused(object sender, EventArgs e) {
     487      algorithmWaitHandle.Set();
     488    }
     489    private void Algorithm_Stopped(object sender, EventArgs e) {
     490      algorithmWaitHandle.Set();
    663491    }
    664492
    665493    private void Algorithm_ProblemChanged(object sender, EventArgs e) {
    666       if (problem != null) DeregisterProblemEvents();
    667 
    668       problem = Algorithm.Problem as ISingleObjectiveHeuristicOptimizationProblem;
    669       if (problem == null) return;
    670       RegisterProblemEvents();
    671 
     494      if (Algorithm.Problem != Problem) Problem = (ISingleObjectiveHeuristicOptimizationProblem)Algorithm.Problem;
    672495      AddAlgorithmAnalyzers();
    673 
    674       var maxParam = problem.MaximizationParameter as IValueParameter<BoolValue>;
    675       if (maxParam != null)
    676         Maximization = maxParam.Value.Value;
    677       var bkParam = problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
    678       if (bkParam != null && bkParam.Value != null)
    679         TargetValue = bkParam.Value.Value;
    680 
    681       Reset();
    682     }
    683 
    684     private void RegisterProblemEvents() {
    685       problem.Reset += ProblemOnReset;
    686       problem.OperatorsChanged += ProblemOnOperatorsChanged;
    687     }
    688 
    689     private void DeregisterProblemEvents() {
    690       problem.Reset -= ProblemOnReset;
    691       problem.OperatorsChanged -= ProblemOnOperatorsChanged;
    692     }
    693 
    694     private void ProblemOnReset(object sender, EventArgs eventArgs) {
    695       AddAlgorithmAnalyzers();
    696     }
    697 
    698     private void ProblemOnOperatorsChanged(object sender, EventArgs eventArgs) {
    699       AddAlgorithmAnalyzers();
    700     }
    701     #endregion
     496    }
     497
     498    private void Problem_BestKnownQualityParameter_ValueChanged(object sender, EventArgs e) {
     499      var param = sender as IValueParameter<DoubleValue>;
     500      if (param != null) {
     501        if (param.Value != null) param.Value.ValueChanged += Problem_BestKnownQualityParameter_Value_ValueChanged;
     502        UpdateTargetValueFromBestKnownQuality();
     503      }
     504    }
     505
     506    private void Problem_BestKnownQualityParameter_Value_ValueChanged(object sender, EventArgs e) {
     507      UpdateTargetValueFromBestKnownQuality();
     508    }
     509
     510    protected override void Problem_Reset(object sender, EventArgs eventArgs) {
     511      if (Algorithm != null) AddAlgorithmAnalyzers();
     512    }
     513
     514    protected override void Problem_OperatorsChanged(object sender, EventArgs eventArgs) {
     515      if (Algorithm != null) AddAlgorithmAnalyzers();
     516    }
     517
     518    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
     519      System.Timers.Timer timer = (System.Timers.Timer)sender;
     520      timer.Enabled = false;
     521      DateTime now = DateTime.UtcNow;
     522      ExecutionTime += now - lastUpdateTime;
     523      lastUpdateTime = now;
     524      timer.Enabled = true;
     525    }
    702526    #endregion
    703527  }
Note: See TracChangeset for help on using the changeset viewer.