Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization/3.3/BatchRun.cs @ 8194

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

#1783:

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