Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Async/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs @ 13354

Last change on this file since 13354 was 13354, checked in by jkarder, 8 years ago

#2258: improved cancellation support

File size: 18.9 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.Drawing;
25using System.Threading;
26using System.Threading.Tasks;
27using HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
32
33namespace HeuristicLab.Optimization {
34  internal enum BatchRunAction { None, Prepare, Start, Pause, Stop };
35
36  /// <summary>
37  /// A run in which an optimizer is executed a given number of times.
38  /// </summary>
39  [Item("Batch Run", "A run in which an optimizer is executed a given number of times.")]
40  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 110)]
41  [StorableClass]
42  public sealed class BatchRun : NamedItem, IOptimizer, IStorableContent {
43    private readonly ManualResetEvent signaler = new ManualResetEvent(true);
44    private CancellationToken cancellationToken;
45
46    public string Filename { get; set; }
47
48    public static new Image StaticItemImage {
49      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
50    }
51    public override Image ItemImage {
52      get {
53        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPrepared;
54        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStarted;
55        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPaused;
56        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStopped;
57        else return base.ItemImage;
58      }
59    }
60
61    [Storable]
62    private ExecutionState executionState;
63    public ExecutionState ExecutionState {
64      get { return executionState; }
65      private set {
66        if (executionState != value) {
67          executionState = value;
68          OnExecutionStateChanged();
69          OnItemImageChanged();
70        }
71      }
72    }
73
74    [Storable]
75    private TimeSpan executionTime;
76    public TimeSpan ExecutionTime {
77      get {
78        if ((Optimizer != null) && (Optimizer.ExecutionState != ExecutionState.Stopped))
79          return executionTime + Optimizer.ExecutionTime;
80        else
81          return executionTime;
82      }
83      private set {
84        executionTime = value;
85        OnExecutionTimeChanged();
86      }
87    }
88
89    [Storable]
90    private TimeSpan runsExecutionTime;
91
92    [Storable]
93    private IOptimizer optimizer;
94    public IOptimizer Optimizer {
95      get { return optimizer; }
96      set {
97        if (optimizer != value) {
98          if (optimizer != null) {
99            DeregisterOptimizerEvents();
100            IEnumerable<IRun> runs = optimizer.Runs;
101            optimizer = null; //necessary to avoid removing the runs from the old optimizer
102            Runs.RemoveRange(runs);
103          }
104          optimizer = value;
105          if (optimizer != null) {
106            RegisterOptimizerEvents();
107            Runs.AddRange(optimizer.Runs);
108          }
109          OnOptimizerChanged();
110          Prepare();
111        }
112      }
113    }
114    // BackwardsCompatibility3.3
115    #region Backwards compatible code (remove with 3.4)
116    [Storable(AllowOneWay = true)]
117    private IAlgorithm algorithm {
118      set { optimizer = value; }
119    }
120    #endregion
121
122    [Storable]
123    private int repetitions;
124    public int Repetitions {
125      get { return repetitions; }
126      set {
127        if (repetitions != value) {
128          repetitions = value;
129          OnRepetitionsChanged();
130          if ((Optimizer != null) && (Optimizer.ExecutionState == ExecutionState.Stopped))
131            Prepare();
132        }
133      }
134    }
135    [Storable]
136    private int repetitionsCounter;
137    public int RepetitionsCounter {
138      get { return repetitionsCounter; }
139      private set {
140        if (value != repetitionsCounter) {
141          repetitionsCounter = value;
142          OnRepetitionsCounterChanged();
143        }
144      }
145    }
146
147    [Storable]
148    private RunCollection runs;
149    public RunCollection Runs {
150      get { return runs; }
151      private set {
152        if (value == null) throw new ArgumentNullException();
153        if (runs != value) {
154          if (runs != null) DeregisterRunsEvents();
155          runs = value;
156          if (runs != null) RegisterRunsEvents();
157        }
158      }
159    }
160
161    public IEnumerable<IOptimizer> NestedOptimizers {
162      get {
163        if (Optimizer == null) yield break;
164
165        yield return Optimizer;
166        foreach (IOptimizer opt in Optimizer.NestedOptimizers)
167          yield return opt;
168      }
169    }
170
171    private BatchRunAction batchRunAction = BatchRunAction.None;
172
173    public BatchRun()
174      : base() {
175      name = ItemName;
176      description = ItemDescription;
177      executionState = ExecutionState.Stopped;
178      executionTime = TimeSpan.Zero;
179      runsExecutionTime = TimeSpan.Zero;
180      repetitions = 10;
181      repetitionsCounter = 0;
182      Runs = new RunCollection { OptimizerName = Name };
183    }
184    public BatchRun(string name)
185      : base(name) {
186      description = ItemDescription;
187      executionState = ExecutionState.Stopped;
188      executionTime = TimeSpan.Zero;
189      runsExecutionTime = TimeSpan.Zero;
190      repetitions = 10;
191      repetitionsCounter = 0;
192      Runs = new RunCollection { OptimizerName = Name };
193    }
194    public BatchRun(string name, string description)
195      : base(name, description) {
196      executionState = ExecutionState.Stopped;
197      executionTime = TimeSpan.Zero;
198      runsExecutionTime = TimeSpan.Zero;
199      repetitions = 10;
200      repetitionsCounter = 0;
201      Runs = new RunCollection { OptimizerName = Name };
202    }
203    [StorableConstructor]
204    private BatchRun(bool deserializing) : base(deserializing) { }
205    [StorableHook(HookType.AfterDeserialization)]
206    private void AfterDeserialization() {
207      Initialize();
208    }
209
210    private BatchRun(BatchRun original, Cloner cloner)
211      : base(original, cloner) {
212      executionState = original.executionState;
213      executionTime = original.executionTime;
214      runsExecutionTime = original.runsExecutionTime;
215      optimizer = cloner.Clone(original.optimizer);
216      repetitions = original.repetitions;
217      repetitionsCounter = original.repetitionsCounter;
218      runs = cloner.Clone(original.runs);
219      batchRunAction = original.batchRunAction;
220      Initialize();
221    }
222    public override IDeepCloneable Clone(Cloner cloner) {
223      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
224      return new BatchRun(this, cloner);
225    }
226
227    private void Initialize() {
228      if (optimizer != null) RegisterOptimizerEvents();
229      if (runs != null) RegisterRunsEvents();
230    }
231
232    public void Prepare() {
233      Prepare(false);
234    }
235    public void Prepare(bool clearRuns) {
236      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
237        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
238      if (Optimizer != null) {
239        ExecutionTime = TimeSpan.Zero;
240        RepetitionsCounter = 0;
241        if (clearRuns) runs.Clear();
242        batchRunAction = BatchRunAction.Prepare;
243        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
244        try { Optimizer.Prepare(clearRuns); }
245        catch (InvalidOperationException) { }
246      } else {
247        ExecutionState = ExecutionState.Stopped;
248      }
249    }
250    public void Start() {
251      StartAsync().Wait();
252    }
253    public async Task StartAsync() {
254      await StartAsync(CancellationToken.None);
255    }
256    public async Task StartAsync(CancellationToken cancellationToken) {
257      this.cancellationToken = cancellationToken;
258      signaler.Reset();
259      await Task.Run(async () => {
260        if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
261          throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
262        if (Optimizer == null) return;
263        batchRunAction = BatchRunAction.Start;
264        if (Optimizer.ExecutionState == ExecutionState.Stopped) Optimizer.Prepare();
265        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
266        try { await Optimizer.StartAsync(cancellationToken); }
267        catch (InvalidOperationException) { }
268        signaler.WaitOne();
269      }, cancellationToken);
270    }
271    public void Pause() {
272      if (ExecutionState != ExecutionState.Started)
273        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
274      if (Optimizer == null) return;
275      batchRunAction = BatchRunAction.Pause;
276      if (Optimizer.ExecutionState != ExecutionState.Started) return;
277      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
278      try { Optimizer.Pause(); }
279      catch (InvalidOperationException) { }
280    }
281    public void Stop() {
282      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
283        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
284      if (Optimizer == null) return;
285      batchRunAction = BatchRunAction.Stop;
286      if (Optimizer.ExecutionState != ExecutionState.Started && Optimizer.ExecutionState != ExecutionState.Paused) {
287        OnStopped();
288        return;
289      }
290      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
291      try { Optimizer.Stop(); }
292      catch (InvalidOperationException) { }
293    }
294
295    #region Events
296    protected override void OnNameChanged() {
297      base.OnNameChanged();
298      runs.OptimizerName = Name;
299    }
300
301    public event EventHandler ExecutionStateChanged;
302    private void OnExecutionStateChanged() {
303      EventHandler handler = ExecutionStateChanged;
304      if (handler != null) handler(this, EventArgs.Empty);
305    }
306    public event EventHandler ExecutionTimeChanged;
307    private void OnExecutionTimeChanged() {
308      EventHandler handler = ExecutionTimeChanged;
309      if (handler != null) handler(this, EventArgs.Empty);
310    }
311    public event EventHandler OptimizerChanged;
312    private void OnOptimizerChanged() {
313      EventHandler handler = OptimizerChanged;
314      if (handler != null) handler(this, EventArgs.Empty);
315    }
316    public event EventHandler RepetitionsChanged;
317    private void OnRepetitionsChanged() {
318      EventHandler handler = RepetitionsChanged;
319      if (handler != null) handler(this, EventArgs.Empty);
320    }
321    public event EventHandler RepetetionsCounterChanged;
322    private void OnRepetitionsCounterChanged() {
323      EventHandler handler = RepetetionsCounterChanged;
324      if (handler != null) handler(this, EventArgs.Empty);
325    }
326    public event EventHandler Prepared;
327    private void OnPrepared() {
328      batchRunAction = BatchRunAction.None;
329      ExecutionState = ExecutionState.Prepared;
330      EventHandler handler = Prepared;
331      if (handler != null) handler(this, EventArgs.Empty);
332    }
333    public event EventHandler Started;
334    private void OnStarted() {
335      // no reset of BatchRunAction.Started, because we need to differ which of the two was started by the user
336      ExecutionState = ExecutionState.Started;
337      EventHandler handler = Started;
338      if (handler != null) handler(this, EventArgs.Empty);
339    }
340    public event EventHandler Paused;
341    private void OnPaused() {
342      batchRunAction = BatchRunAction.None;
343      ExecutionState = ExecutionState.Paused;
344      signaler.Set();
345      EventHandler handler = Paused;
346      if (handler != null) handler(this, EventArgs.Empty);
347    }
348    public event EventHandler Stopped;
349    private void OnStopped() {
350      batchRunAction = BatchRunAction.None;
351      ExecutionState = ExecutionState.Stopped;
352      signaler.Set();
353      EventHandler handler = Stopped;
354      if (handler != null) handler(this, EventArgs.Empty);
355    }
356    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
357    private void OnExceptionOccurred(Exception exception) {
358      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
359      if (handler != null) handler(this, new EventArgs<Exception>(exception));
360    }
361
362    private void RegisterOptimizerEvents() {
363      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
364      optimizer.ExecutionTimeChanged += new EventHandler(Optimizer_ExecutionTimeChanged);
365      optimizer.Paused += new EventHandler(Optimizer_Paused);
366      optimizer.Prepared += new EventHandler(Optimizer_Prepared);
367      optimizer.Started += new EventHandler(Optimizer_Started);
368      optimizer.Stopped += new EventHandler(Optimizer_Stopped);
369      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
370      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
371      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
372    }
373    private void DeregisterOptimizerEvents() {
374      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
375      optimizer.ExecutionTimeChanged -= new EventHandler(Optimizer_ExecutionTimeChanged);
376      optimizer.Paused -= new EventHandler(Optimizer_Paused);
377      optimizer.Prepared -= new EventHandler(Optimizer_Prepared);
378      optimizer.Started -= new EventHandler(Optimizer_Started);
379      optimizer.Stopped -= new EventHandler(Optimizer_Stopped);
380      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
381      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
382      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
383    }
384    private void Optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
385      OnExceptionOccurred(e.Value);
386    }
387    private void Optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
388      OnExecutionTimeChanged();
389    }
390    private void Optimizer_Paused(object sender, EventArgs e) {
391      if (ExecutionState == ExecutionState.Started) {
392        OnPaused();
393      }
394    }
395    private void Optimizer_Prepared(object sender, EventArgs e) {
396      if (batchRunAction == BatchRunAction.Prepare || ExecutionState == ExecutionState.Stopped) {
397        ExecutionTime = TimeSpan.Zero;
398        runsExecutionTime = TimeSpan.Zero;
399        RepetitionsCounter = 0;
400        OnPrepared();
401      }
402    }
403    private void Optimizer_Started(object sender, EventArgs e) {
404      if (ExecutionState != ExecutionState.Started)
405        OnStarted();
406    }
407    private void Optimizer_Stopped(object sender, EventArgs e) {
408      RepetitionsCounter++;
409      ExecutionTime += runsExecutionTime;
410      runsExecutionTime = TimeSpan.Zero;
411
412      if (batchRunAction == BatchRunAction.Stop) OnStopped();
413      else if (repetitionsCounter >= repetitions) OnStopped();
414      else if (batchRunAction == BatchRunAction.Pause) OnPaused();
415      else if (batchRunAction == BatchRunAction.Start) {
416        Optimizer.Prepare();
417        Optimizer.StartAsync(cancellationToken);
418      } else if (executionState == ExecutionState.Started) {
419        // if the batch run hasn't been started but the inner optimizer was run then pause
420        OnPaused();
421      } else OnStopped();
422    }
423    private void Optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
424      Runs.RemoveRange(e.OldItems);
425      Runs.AddRange(e.Items);
426    }
427    private void Optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
428      Runs.AddRange(e.Items);
429    }
430    private void Optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
431      Runs.RemoveRange(e.Items);
432    }
433
434    private void RegisterRunsEvents() {
435      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
436      runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
437      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
438    }
439
440    private void DeregisterRunsEvents() {
441      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
442      runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
443      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
444    }
445    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
446      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.OldItems);
447      foreach (IRun run in e.Items) {
448        IItem item;
449        run.Results.TryGetValue("Execution Time", out item);
450        TimeSpanValue executionTime = item as TimeSpanValue;
451        if (executionTime != null) ExecutionTime += executionTime.Value;
452      }
453    }
454    private void Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
455      foreach (IRun run in e.Items) {
456        IItem item;
457        run.Results.TryGetValue("Execution Time", out item);
458        TimeSpanValue executionTime = item as TimeSpanValue;
459        if (executionTime != null) {
460          if (Optimizer.ExecutionState == ExecutionState.Started)
461            runsExecutionTime += executionTime.Value;
462          else
463            ExecutionTime += executionTime.Value;
464        }
465      }
466    }
467    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
468      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.Items);
469    }
470    #endregion
471  }
472}
Note: See TracBrowser for help on using the repository browser.