source: trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs @ 13321

Last change on this file since 13321 was 13321, checked in by ascheibe, 4 years ago

#2428 merged r13316, r13317, r13319 from stable back into trunk

File size: 13.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Tasks;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Common.Resources;
31using HeuristicLab.Core;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33
34namespace HeuristicLab.Optimization {
35  /// <summary>
36  /// A run in which an algorithm is executed for a certain maximum time only.
37  /// </summary>
38  [Item("Timelimit Run", "A run in which an optimizer is executed a certain maximum time.")]
39  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 115)]
40  [StorableClass]
41  public sealed class TimeLimitRun : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
42    public string Filename { get; set; }
43
44    #region ItemImage
45    public static new Image StaticItemImage {
46      get { return VSImageLibrary.Event; }
47    }
48    public override Image ItemImage {
49      get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
50    }
51    #endregion
52
53    private bool pausedForSnapshot = false;
54    private bool pausedForTermination = false;
55
56    [Storable]
57    private TimeSpan maximumExecutionTime;
58    public TimeSpan MaximumExecutionTime {
59      get { return maximumExecutionTime; }
60      set {
61        if (maximumExecutionTime == value) return;
62        maximumExecutionTime = value;
63        OnPropertyChanged("MaximumExecutionTime");
64      }
65    }
66
67    [Storable]
68    private int snapshotTimesIndex;
69    [Storable]
70    private ObservableList<TimeSpan> snapshotTimes;
71    public ObservableList<TimeSpan> SnapshotTimes {
72      get { return snapshotTimes; }
73      set {
74        if (snapshotTimes == value) return;
75        snapshotTimes = value;
76        snapshotTimes.Sort();
77        FindNextSnapshotTimeIndex(ExecutionTime);
78        OnPropertyChanged("SnapshotTimes");
79      }
80    }
81
82    [Storable]
83    private bool storeAlgorithmInEachSnapshot;
84    [Storable]
85    public bool StoreAlgorithmInEachSnapshot {
86      get { return storeAlgorithmInEachSnapshot; }
87      set {
88        if (storeAlgorithmInEachSnapshot == value) return;
89        storeAlgorithmInEachSnapshot = value;
90        OnPropertyChanged("StoreAlgorithmInEachSnapshot");
91      }
92    }
93
94    [Storable]
95    private RunCollection snapshots;
96    public RunCollection Snapshots {
97      get { return snapshots; }
98      set {
99        if (snapshots == value) return;
100        snapshots = value;
101        OnPropertyChanged("Snapshots");
102      }
103    }
104
105    #region Inherited Properties
106    public ExecutionState ExecutionState {
107      get { return (Algorithm != null) ? Algorithm.ExecutionState : ExecutionState.Stopped; }
108    }
109
110    public TimeSpan ExecutionTime {
111      get { return (Algorithm != null) ? Algorithm.ExecutionTime : TimeSpan.FromSeconds(0); }
112    }
113
114    [Storable]
115    private IAlgorithm algorithm;
116    public IAlgorithm Algorithm {
117      get { return algorithm; }
118      set {
119        if (algorithm == value) return;
120        if (algorithm != null) DeregisterAlgorithmEvents();
121        algorithm = value;
122        if (algorithm != null) {
123          RegisterAlgorithmEvents();
124        }
125        OnPropertyChanged("Algorithm");
126        Prepare();
127      }
128    }
129
130    [Storable]
131    private RunCollection runs;
132    public RunCollection Runs {
133      get { return runs; }
134      private set {
135        if (value == null) throw new ArgumentNullException();
136        if (runs == value) return;
137        runs = value;
138        OnPropertyChanged("Runs");
139      }
140    }
141
142    public IEnumerable<IOptimizer> NestedOptimizers {
143      get {
144        if (Algorithm == null) yield break;
145        yield return Algorithm;
146        foreach (var opt in Algorithm.NestedOptimizers)
147          yield return opt;
148      }
149    }
150    #endregion
151
152    [StorableConstructor]
153    private TimeLimitRun(bool deserializing) : base(deserializing) { }
154    private TimeLimitRun(TimeLimitRun original, Cloner cloner)
155      : base(original, cloner) {
156      maximumExecutionTime = original.maximumExecutionTime;
157      snapshotTimes = new ObservableList<TimeSpan>(original.snapshotTimes);
158      snapshotTimesIndex = original.snapshotTimesIndex;
159      snapshots = cloner.Clone(original.snapshots);
160      storeAlgorithmInEachSnapshot = original.storeAlgorithmInEachSnapshot;
161      algorithm = cloner.Clone(original.algorithm);
162      runs = cloner.Clone(original.runs);
163
164      Initialize();
165    }
166    public TimeLimitRun()
167      : base() {
168      name = ItemName;
169      description = ItemDescription;
170      maximumExecutionTime = TimeSpan.FromMinutes(.5);
171      snapshotTimes = new ObservableList<TimeSpan>(new[] {
172          TimeSpan.FromSeconds(5),
173          TimeSpan.FromSeconds(10),
174          TimeSpan.FromSeconds(15) });
175      snapshotTimesIndex = 0;
176      snapshots = new RunCollection();
177      Runs = new RunCollection { OptimizerName = Name };
178      Initialize();
179    }
180    public TimeLimitRun(string name)
181      : base(name) {
182      description = ItemDescription;
183      maximumExecutionTime = TimeSpan.FromMinutes(.5);
184      snapshotTimes = new ObservableList<TimeSpan>(new[] {
185          TimeSpan.FromSeconds(5),
186          TimeSpan.FromSeconds(10),
187          TimeSpan.FromSeconds(15) });
188      snapshotTimesIndex = 0;
189      Runs = new RunCollection { OptimizerName = Name };
190      Initialize();
191    }
192    public TimeLimitRun(string name, string description)
193      : base(name, description) {
194      maximumExecutionTime = TimeSpan.FromMinutes(.5);
195      snapshotTimes = new ObservableList<TimeSpan>(new[] {
196          TimeSpan.FromSeconds(5),
197          TimeSpan.FromSeconds(10),
198          TimeSpan.FromSeconds(15) });
199      snapshotTimesIndex = 0;
200      Runs = new RunCollection { OptimizerName = Name };
201      Initialize();
202    }
203
204    public override IDeepCloneable Clone(Cloner cloner) {
205      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
206      return new TimeLimitRun(this, cloner);
207    }
208
209    [StorableHook(HookType.AfterDeserialization)]
210    private void AfterDeserialization() {
211      Initialize();
212    }
213
214    private void Initialize() {
215      if (algorithm != null) RegisterAlgorithmEvents();
216      snapshotTimes.ItemsAdded += snapshotTimes_Changed;
217      snapshotTimes.ItemsMoved += snapshotTimes_Changed;
218      snapshotTimes.ItemsRemoved += snapshotTimes_Changed;
219      snapshotTimes.ItemsReplaced += snapshotTimes_Changed;
220      snapshotTimes.CollectionReset += snapshotTimes_Changed;
221    }
222
223    private void snapshotTimes_Changed(object sender, CollectionItemsChangedEventArgs<IndexedItem<TimeSpan>> e) {
224      if (e.Items.Any()) snapshotTimes.Sort();
225      FindNextSnapshotTimeIndex(ExecutionTime);
226    }
227
228    public void Snapshot() {
229      if (Algorithm == null || Algorithm.ExecutionState != ExecutionState.Paused) throw new InvalidOperationException("Snapshot not allowed in execution states other than Paused");
230      Task.Factory.StartNew(MakeSnapshot);
231    }
232
233    public void Prepare() {
234      Prepare(false);
235    }
236    public void Prepare(bool clearRuns) {
237      Algorithm.Prepare(clearRuns);
238    }
239    public void Start() {
240      Algorithm.Start();
241    }
242    public void Pause() {
243      Algorithm.Pause();
244    }
245    public void Stop() {
246      Algorithm.Stop();
247    }
248
249    #region Events
250    protected override void OnNameChanged() {
251      base.OnNameChanged();
252      runs.OptimizerName = Name;
253    }
254
255    public event PropertyChangedEventHandler PropertyChanged;
256    private void OnPropertyChanged(string property) {
257      var handler = PropertyChanged;
258      if (handler != null) handler(this, new PropertyChangedEventArgs(property));
259    }
260
261    #region IExecutable Events
262    public event EventHandler ExecutionStateChanged;
263    private void OnExecutionStateChanged() {
264      var handler = ExecutionStateChanged;
265      if (handler != null) handler(this, EventArgs.Empty);
266    }
267    public event EventHandler ExecutionTimeChanged;
268    private void OnExecutionTimeChanged() {
269      var handler = ExecutionTimeChanged;
270      if (handler != null) handler(this, EventArgs.Empty);
271    }
272    public event EventHandler Prepared;
273    private void OnPrepared() {
274      var handler = Prepared;
275      if (handler != null) handler(this, EventArgs.Empty);
276    }
277    public event EventHandler Started;
278    private void OnStarted() {
279      var handler = Started;
280      if (handler != null) handler(this, EventArgs.Empty);
281    }
282    public event EventHandler Paused;
283    private void OnPaused() {
284      var handler = Paused;
285      if (handler != null) handler(this, EventArgs.Empty);
286    }
287    public event EventHandler Stopped;
288    private void OnStopped() {
289      var handler = Stopped;
290      if (handler != null) handler(this, EventArgs.Empty);
291    }
292    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
293    private void OnExceptionOccurred(Exception exception) {
294      var handler = ExceptionOccurred;
295      if (handler != null) handler(this, new EventArgs<Exception>(exception));
296    }
297    #endregion
298
299    #region Algorithm Events
300    private void RegisterAlgorithmEvents() {
301      algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
302      algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
303      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
304      algorithm.Paused += Algorithm_Paused;
305      algorithm.Prepared += Algorithm_Prepared;
306      algorithm.Started += Algorithm_Started;
307      algorithm.Stopped += Algorithm_Stopped;
308    }
309    private void DeregisterAlgorithmEvents() {
310      algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
311      algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
312      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
313      algorithm.Paused -= Algorithm_Paused;
314      algorithm.Prepared -= Algorithm_Prepared;
315      algorithm.Started -= Algorithm_Started;
316      algorithm.Stopped -= Algorithm_Stopped;
317    }
318    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
319      OnExceptionOccurred(e.Value);
320    }
321    private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
322      if (snapshotTimesIndex < SnapshotTimes.Count && ExecutionTime >= SnapshotTimes[snapshotTimesIndex]
323        && !pausedForSnapshot) {
324        pausedForSnapshot = true;
325        Algorithm.Pause();
326      }
327      if (ExecutionTime >= MaximumExecutionTime && !pausedForTermination) {
328        pausedForTermination = true;
329        if (!pausedForSnapshot) Algorithm.Pause();
330      }
331      OnExecutionTimeChanged();
332    }
333    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
334      OnExecutionStateChanged();
335    }
336    private void Algorithm_Paused(object sender, EventArgs e) {
337      var action = pausedForTermination ? ExecutionState.Stopped : (pausedForSnapshot ? ExecutionState.Started : ExecutionState.Paused);
338      if (pausedForSnapshot || pausedForTermination) {
339        pausedForSnapshot = pausedForTermination = false;
340        MakeSnapshot();
341        FindNextSnapshotTimeIndex(ExecutionTime);
342      }
343      OnPaused();
344      if (action == ExecutionState.Started) Algorithm.Start();
345      else if (action == ExecutionState.Stopped) Algorithm.Stop();
346    }
347    private void Algorithm_Prepared(object sender, EventArgs e) {
348      snapshotTimesIndex = 0;
349      snapshots.Clear();
350      OnPrepared();
351    }
352    private void Algorithm_Started(object sender, EventArgs e) {
353      OnStarted();
354    }
355    private void Algorithm_Stopped(object sender, EventArgs e) {
356      var cloner = new Cloner();
357      var algRun = cloner.Clone(Algorithm.Runs.Last());
358      var clonedSnapshots = cloner.Clone(snapshots);
359      algRun.Results.Add("TimeLimitRunSnapshots", clonedSnapshots);
360      Runs.Add(algRun);
361      Algorithm.Runs.Clear();
362      OnStopped();
363    }
364    #endregion
365    #endregion
366
367    private void FindNextSnapshotTimeIndex(TimeSpan reference) {
368      var index = 0;
369      while (index < snapshotTimes.Count && snapshotTimes[index] <= reference) {
370        index++;
371      };
372      snapshotTimesIndex = index;
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      var changed = false;
379      if (StoreAlgorithmInEachSnapshot && !Algorithm.StoreAlgorithmInEachRun) {
380        Algorithm.StoreAlgorithmInEachRun = true;
381        changed = true;
382      } else if (!StoreAlgorithmInEachSnapshot && Algorithm.StoreAlgorithmInEachRun) {
383        Algorithm.StoreAlgorithmInEachRun = false;
384        changed = true;
385      }
386      var run = new Run(runName, Algorithm);
387      if (changed)
388        Algorithm.StoreAlgorithmInEachRun = !Algorithm.StoreAlgorithmInEachRun;
389
390      snapshots.Add(run);
391    }
392  }
393}
Note: See TracBrowser for help on using the repository browser.