Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RuntimeOptimizer/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs @ 8961

Last change on this file since 8961 was 8961, checked in by abeham, 12 years ago

#1985: added ability to edit snapshot times (changed representation to a list of timespan instead of a list of double)

File size: 19.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Threading;
28using System.Threading.Tasks;
29using System.Timers;
30using HeuristicLab.Collections;
31using HeuristicLab.Common;
32using HeuristicLab.Common.Resources;
33using HeuristicLab.Core;
34using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
35using Timer = System.Timers.Timer;
36
37namespace HeuristicLab.Optimization {
38  internal enum TimeLimitedRunAction { None, Prepare, Start, Pause, Stop };
39
40  /// <summary>
41  /// A run in which an algorithm is executed for a certain maximum time only.
42  /// </summary>
43  [Item("TimeLimitRun", "A run in which an optimizer is executed a certain maximum time.")]
44  [Creatable("Testing & Analysis")]
45  [StorableClass]
46  public sealed class TimeLimitRun : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
47    public string Filename { get; set; }
48
49    #region ItemImage
50    public static new Image StaticItemImage {
51      get { return VSImageLibrary.Event; }
52    }
53    public override Image ItemImage {
54      get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
55    }
56    #endregion
57
58    private Timer snapTimer, runTimer;
59    private readonly ManualResetEvent algorithmStarted = new ManualResetEvent(false);
60    private readonly ManualResetEvent algorithmPaused = new ManualResetEvent(false);
61    private readonly ManualResetEvent algorithmStopped = new ManualResetEvent(false);
62    [Storable]
63    private bool snapshotTimesDirty;
64
65    [Storable]
66    private TimeSpan maximumExecutionTime;
67    public TimeSpan MaximumExecutionTime {
68      get { return maximumExecutionTime; }
69      set {
70        if (maximumExecutionTime == value) return;
71        maximumExecutionTime = value;
72        runTimer.Interval = (maximumExecutionTime - ExecutionTime).TotalMilliseconds;
73        OnPropertyChanged("MaximumExecutionTime");
74      }
75    }
76
77    [Storable]
78    private int snapshotTimesIndex;
79    [Storable]
80    private ObservableList<TimeSpan> snapshotTimes;
81    public ObservableList<TimeSpan> SnapshotTimes {
82      get { return snapshotTimes; }
83      set {
84        if (snapshotTimes == value) return;
85        snapshotTimes = value;
86        snapshotTimesDirty = true;
87        OnPropertyChanged("SnapshotTimes");
88      }
89    }
90
91    [Storable]
92    private bool storeAlgorithmInEachSnapshot;
93    [Storable]
94    public bool StoreAlgorithmInEachSnapshot {
95      get { return storeAlgorithmInEachSnapshot; }
96      set {
97        if (storeAlgorithmInEachSnapshot == value) return;
98        storeAlgorithmInEachSnapshot = value;
99        OnPropertyChanged("StoreAlgorithmInEachSnapshot");
100      }
101    }
102
103    [Storable]
104    private RunCollection snapshots;
105    public RunCollection Snapshots {
106      get { return snapshots; }
107      set {
108        if (snapshots == value) return;
109        snapshots = value;
110        OnPropertyChanged("Snapshots");
111      }
112    }
113
114    #region Inherited Properties
115    public ExecutionState ExecutionState {
116      get { return (Algorithm != null) ? Algorithm.ExecutionState : ExecutionState.Stopped; }
117    }
118
119    public TimeSpan ExecutionTime {
120      get { return (Algorithm != null) ? Algorithm.ExecutionTime : TimeSpan.FromSeconds(0); }
121    }
122
123    [Storable]
124    private IAlgorithm algorithm;
125    public IAlgorithm Algorithm {
126      get { return algorithm; }
127      set {
128        if (algorithm == value) return;
129        if (algorithm != null) DeregisterAlgorithmEvents();
130        algorithm = value;
131        if (algorithm != null) {
132          RegisterAlgorithmEvents();
133          if (algorithm.ExecutionState == ExecutionState.Started) algorithmStarted.Set();
134          else algorithmStarted.Reset();
135          if (algorithm.ExecutionState == ExecutionState.Paused) algorithmPaused.Set();
136          else algorithmPaused.Reset();
137          if (algorithm.ExecutionState == ExecutionState.Stopped) algorithmStopped.Set();
138          else algorithmStopped.Reset();
139        }
140        OnPropertyChanged("Algorithm");
141        Prepare();
142      }
143    }
144
145    [Storable]
146    private RunCollection runs;
147    public RunCollection Runs {
148      get { return runs; }
149      private set {
150        if (value == null) throw new ArgumentNullException();
151        if (runs == value) return;
152        runs = value;
153        OnPropertyChanged("Runs");
154      }
155    }
156
157    public IEnumerable<IOptimizer> NestedOptimizers {
158      get {
159        if (Algorithm == null) yield break;
160        yield return Algorithm;
161        foreach (var opt in Algorithm.NestedOptimizers)
162          yield return opt;
163      }
164    }
165    #endregion
166
167    [StorableConstructor]
168    private TimeLimitRun(bool deserializing) : base(deserializing) { }
169    private TimeLimitRun(TimeLimitRun original, Cloner cloner)
170      : base(original, cloner) {
171      maximumExecutionTime = original.maximumExecutionTime;
172      snapshotTimes = new ObservableList<TimeSpan>(original.snapshotTimes);
173      snapshotTimesIndex = original.snapshotTimesIndex;
174      snapshots = cloner.Clone(original.snapshots);
175      snapshotTimesDirty = original.snapshotTimesDirty;
176      storeAlgorithmInEachSnapshot = original.storeAlgorithmInEachSnapshot;
177      algorithm = cloner.Clone(original.algorithm);
178      runs = cloner.Clone(original.runs);
179
180      snapTimer = new Timer() {
181        AutoReset = original.snapTimer.AutoReset,
182        Interval = original.snapTimer.Interval
183      };
184      runTimer = new Timer() {
185        AutoReset = original.runTimer.AutoReset,
186        Interval = original.runTimer.Interval
187      };
188      if (original.algorithm != null && original.algorithm.ExecutionState == ExecutionState.Started)
189        algorithmStarted.Set();
190      if (original.algorithm != null && original.algorithm.ExecutionState == ExecutionState.Paused)
191        algorithmPaused.Set();
192      if (original.algorithm != null && original.algorithm.ExecutionState == ExecutionState.Stopped)
193        algorithmStopped.Set();
194
195      Initialize();
196    }
197    public TimeLimitRun()
198      : base() {
199      name = ItemName;
200      description = ItemDescription;
201      maximumExecutionTime = TimeSpan.FromMinutes(1);
202      snapshotTimes = new ObservableList<TimeSpan>(new[] {
203          TimeSpan.FromSeconds(5),
204          TimeSpan.FromSeconds(10),
205          TimeSpan.FromSeconds(30) });
206      snapshotTimesIndex = 0;
207      snapTimer = new Timer() {
208        AutoReset = false,
209        Enabled = false,
210        Interval = 100
211      };
212      runTimer = new Timer() {
213        AutoReset = false,
214        Enabled = false,
215        Interval = MaximumExecutionTime.TotalMilliseconds
216      };
217      snapshots = new RunCollection();
218      Runs = new RunCollection { AlgorithmName = Name };
219      Initialize();
220    }
221    public TimeLimitRun(string name)
222      : base(name) {
223      description = ItemDescription;
224      maximumExecutionTime = TimeSpan.FromMinutes(1);
225      snapshotTimes = new ObservableList<TimeSpan>(new[] {
226          TimeSpan.FromSeconds(5),
227          TimeSpan.FromSeconds(10),
228          TimeSpan.FromSeconds(30) });
229      snapshotTimesIndex = 0;
230      snapTimer = new Timer() {
231        AutoReset = false,
232        Enabled = false,
233        Interval = 100
234      };
235      snapshots = new RunCollection();
236      runTimer = new Timer() {
237        AutoReset = false,
238        Enabled = false,
239        Interval = MaximumExecutionTime.TotalMilliseconds
240      };
241      Runs = new RunCollection { AlgorithmName = Name };
242      Initialize();
243    }
244    public TimeLimitRun(string name, string description)
245      : base(name, description) {
246      maximumExecutionTime = TimeSpan.FromMinutes(1);
247      snapshotTimes = new ObservableList<TimeSpan>(new[] {
248          TimeSpan.FromSeconds(5),
249          TimeSpan.FromSeconds(10),
250          TimeSpan.FromSeconds(30) });
251      snapshotTimesIndex = 0;
252      snapTimer = new Timer() {
253        AutoReset = false,
254        Enabled = false,
255        Interval = 100
256      };
257      snapshots = new RunCollection();
258      runTimer = new Timer() {
259        AutoReset = false,
260        Enabled = false,
261        Interval = MaximumExecutionTime.TotalMilliseconds
262      };
263      Runs = new RunCollection { AlgorithmName = Name };
264      Initialize();
265    }
266
267    public override IDeepCloneable Clone(Cloner cloner) {
268      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
269      return new TimeLimitRun(this, cloner);
270    }
271
272    [StorableHook(HookType.AfterDeserialization)]
273    private void AfterDeserialization() {
274      // the timers will not be serialized
275      snapTimer = new Timer() {
276        AutoReset = false,
277        Enabled = false,
278        Interval = 100
279      };
280      runTimer = new Timer() {
281        AutoReset = false,
282        Enabled = false,
283        Interval = double.MaxValue
284      };
285      if (Algorithm != null && Algorithm.ExecutionState == ExecutionState.Started)
286        algorithmStarted.Set();
287      else algorithmStarted.Reset();
288      if (Algorithm != null && Algorithm.ExecutionState == ExecutionState.Paused)
289        algorithmPaused.Set();
290      else algorithmPaused.Reset();
291      if (Algorithm != null && Algorithm.ExecutionState == ExecutionState.Stopped)
292        algorithmStopped.Set();
293      else algorithmStopped.Reset();
294      Initialize();
295    }
296
297    private void Initialize() {
298      if (algorithm != null) RegisterAlgorithmEvents();
299      snapshotTimes.ItemsAdded += snapshotTimes_Changed;
300      snapshotTimes.ItemsMoved += snapshotTimes_Changed;
301      snapshotTimes.ItemsRemoved += snapshotTimes_Changed;
302      snapshotTimes.ItemsReplaced += snapshotTimes_Changed;
303      snapshotTimes.CollectionReset += snapshotTimes_Changed;
304      snapTimer.Elapsed += snapshotTimer_Elapsed;
305      runTimer.Elapsed += runTimer_Elapsed;
306    }
307
308    private void snapshotTimes_Changed(object sender, EventArgs e) {
309      snapshotTimesDirty = true;
310    }
311
312    private readonly object snapshotLock = new object();
313    private void snapshotTimer_Elapsed(object sender, ElapsedEventArgs e) {
314      snapTimer.Stop();
315      lock (snapshotLock) {
316        try {
317          if (Algorithm == null) return;
318          if (ExecutionState != ExecutionState.Started) return;
319
320          var execTime = ExecutionTime;
321          if (snapshotTimesIndex < SnapshotTimes.Count &&
322              SnapshotTimes[snapshotTimesIndex] <= execTime) {
323            DoSnapshot();
324            snapshotTimesIndex++;
325            try {
326              Algorithm.Start();
327              algorithmStarted.WaitOne();
328            } catch (InvalidOperationException) { }
329          }
330        } catch { }
331        snapTimer.Start();
332      }
333    }
334
335    private void runTimer_Elapsed(object sender, ElapsedEventArgs e) {
336      snapTimer.Stop();
337      lock (snapshotLock) {
338        try {
339          Algorithm.Stop();
340          algorithmStopped.WaitOne();
341        } catch (InvalidOperationException) { }
342      }
343    }
344
345    private void FindNextSnapshotTimeIndex(TimeSpan reference) {
346      var index = 0;
347      while (index < snapshotTimes.Count && snapshotTimes[index] <= reference) {
348        index++;
349      };
350      snapshotTimesIndex = index;
351    }
352
353    private void DoSnapshot() {
354      lock (snapshotLock) {
355        var wasPaused = Algorithm.ExecutionState == ExecutionState.Paused;
356        var error = false;
357        try {
358          Algorithm.Pause();
359          algorithmPaused.WaitOne();
360        } catch (InvalidOperationException) {
361          error = true;
362        }
363        if (error && ExecutionState != ExecutionState.Paused) return; // Algorithm is either stopped or prepared
364
365        MakeSnapshot();
366        if (!wasPaused) {
367          try {
368            Algorithm.Start();
369            algorithmStarted.WaitOne();
370          } catch (InvalidOperationException) { }
371        }
372      }
373    }
374
375    private void MakeSnapshot() {
376      string time = Math.Round(ExecutionTime.TotalSeconds, 1).ToString("0.0");
377      string runName = "Snapshot " + time + "s " + algorithm.Name;
378      Run run;
379      if (StoreAlgorithmInEachSnapshot) {
380        var temporarilySetStoreFlag = !Algorithm.StoreAlgorithmInEachRun;
381        if (temporarilySetStoreFlag) Algorithm.StoreAlgorithmInEachRun = true;
382        run = new Run(runName, Algorithm);
383        if (temporarilySetStoreFlag) Algorithm.StoreAlgorithmInEachRun = false;
384      } else {
385        // duplicate code of Run.Initialize - necessary, because Algorithm property doesn't have a setter
386        run = new Run() { Name = runName };
387        var parameters = new Dictionary<string, IItem>();
388        var results = new Dictionary<string, IItem>();
389        algorithm.CollectParameterValues(parameters);
390        algorithm.CollectResultValues(results);
391        var cloner = new Cloner();
392        foreach (var kvp in parameters.Select(x => new KeyValuePair<string, IItem>(x.Key, cloner.Clone(x.Value))).ToDictionary(x => x.Key, x => x.Value))
393          run.Parameters.Add(kvp);
394        foreach (var kvp in results.Select(x => new KeyValuePair<string, IItem>(x.Key, cloner.Clone(x.Value))).ToDictionary(x => x.Key, x => x.Value))
395          run.Results.Add(kvp);
396      }
397      snapshots.Add(run);
398    }
399
400    public void Snapshot() {
401      Task.Factory.StartNew(DoSnapshot);
402    }
403
404    public void Prepare() {
405      Prepare(false);
406    }
407    public void Prepare(bool clearRuns) {
408      Algorithm.Prepare(clearRuns);
409    }
410    public void Start() {
411      Algorithm.Start();
412    }
413    public void Pause() {
414      Algorithm.Pause();
415    }
416    public void Stop() {
417      Algorithm.Stop();
418    }
419
420    #region Events
421    protected override void OnNameChanged() {
422      base.OnNameChanged();
423      runs.AlgorithmName = Name;
424    }
425
426    public event PropertyChangedEventHandler PropertyChanged;
427    private void OnPropertyChanged(string property) {
428      var handler = PropertyChanged;
429      if (handler != null) handler(this, new PropertyChangedEventArgs(property));
430    }
431
432    #region IExecutable Events
433    public event EventHandler ExecutionStateChanged;
434    private void OnExecutionStateChanged() {
435      var handler = ExecutionStateChanged;
436      if (handler != null) handler(this, EventArgs.Empty);
437    }
438    public event EventHandler ExecutionTimeChanged;
439    private void OnExecutionTimeChanged() {
440      var handler = ExecutionTimeChanged;
441      if (handler != null) handler(this, EventArgs.Empty);
442    }
443    public event EventHandler Prepared;
444    private void OnPrepared() {
445      var handler = Prepared;
446      if (handler != null) handler(this, EventArgs.Empty);
447    }
448    public event EventHandler Started;
449    private void OnStarted() {
450      var handler = Started;
451      if (handler != null) handler(this, EventArgs.Empty);
452    }
453    public event EventHandler Paused;
454    private void OnPaused() {
455      var handler = Paused;
456      if (handler != null) handler(this, EventArgs.Empty);
457    }
458    public event EventHandler Stopped;
459    private void OnStopped() {
460      var handler = Stopped;
461      if (handler != null) handler(this, EventArgs.Empty);
462    }
463    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
464    private void OnExceptionOccurred(Exception exception) {
465      var handler = ExceptionOccurred;
466      if (handler != null) handler(this, new EventArgs<Exception>(exception));
467    }
468    #endregion
469
470    #region Algorithm Events
471    private void RegisterAlgorithmEvents() {
472      algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
473      algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
474      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
475      algorithm.Paused += Algorithm_Paused;
476      algorithm.Prepared += Algorithm_Prepared;
477      algorithm.Started += Algorithm_Started;
478      algorithm.Stopped += Algorithm_Stopped;
479    }
480    private void DeregisterAlgorithmEvents() {
481      algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
482      algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
483      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
484      algorithm.Paused -= Algorithm_Paused;
485      algorithm.Prepared -= Algorithm_Prepared;
486      algorithm.Started -= Algorithm_Started;
487      algorithm.Stopped -= Algorithm_Stopped;
488    }
489    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
490      OnExceptionOccurred(e.Value);
491    }
492    private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
493      OnExecutionTimeChanged();
494    }
495    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
496      OnExecutionStateChanged();
497    }
498    private void Algorithm_Paused(object sender, EventArgs e) {
499      algorithmStarted.Reset();
500      algorithmPaused.Set();
501      algorithmStopped.Reset();
502      OnPaused();
503    }
504    private void Algorithm_Prepared(object sender, EventArgs e) {
505      algorithmStarted.Reset();
506      algorithmPaused.Reset();
507      algorithmStopped.Reset();
508      snapTimer.Stop();
509      runTimer.Stop();
510      snapshotTimesIndex = 0;
511      snapshots.Clear();
512      OnPrepared();
513    }
514    private void Algorithm_Started(object sender, EventArgs e) {
515      algorithmStarted.Set();
516      algorithmPaused.Reset();
517      algorithmStopped.Reset();
518      var execTime = ExecutionTime;
519      if (snapshotTimesDirty) {
520        SnapshotTimes.Sort();
521        snapshotTimesDirty = false; // sort will mark it dirty again
522        FindNextSnapshotTimeIndex(execTime);
523      }
524      runTimer.Interval = (MaximumExecutionTime - execTime).TotalMilliseconds;
525      snapTimer.Start();
526      runTimer.Start();
527      OnStarted();
528    }
529    private void Algorithm_Stopped(object sender, EventArgs e) {
530      algorithmStarted.Reset();
531      algorithmPaused.Reset();
532      algorithmStopped.Set();
533      lock (snapshotLock) {
534        snapTimer.Stop();
535        runTimer.Stop();
536        MakeSnapshot();
537      }
538      var cloner = new Cloner();
539      var algRun = cloner.Clone(Algorithm.Runs.Last());
540      var clonedSnapshots = cloner.Clone(snapshots);
541      try {
542        algRun.Results.Add("Snapshots", clonedSnapshots);
543      } catch (ArgumentException ex) {
544        // TODO strategy?
545      }
546      Runs.Add(algRun);
547      Algorithm.Runs.Clear();
548      OnStopped();
549    }
550    #endregion
551    #endregion
552  }
553}
Note: See TracBrowser for help on using the repository browser.