Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GeneralizedQAP/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs @ 15603

Last change on this file since 15603 was 15603, checked in by abeham, 6 years ago

#1614: Implemented changed behavior to measure execution time (cf. #2869)

File size: 18.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.Linq;
26using System.Threading;
27using System.Threading.Tasks;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
32
33namespace HeuristicLab.Optimization {
34  /// <summary>
35  /// An experiment which contains multiple algorithms, batch runs or other experiments.
36  /// </summary>
37  [Item("Experiment", "An experiment which contains multiple algorithms, batch runs or other experiments.")]
38  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 100)]
39  [StorableClass]
40  public sealed class Experiment : 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.ExperimentPrepared;
49        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStarted;
50        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentPaused;
51        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStopped;
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 { return executionTime + Optimizers.Aggregate(TimeSpan.Zero, (a, x) => a + x.ExecutionTime); }
73    }
74
75    [Storable]
76    private OptimizerList optimizers;
77    public OptimizerList Optimizers {
78      get { return optimizers; }
79    }
80
81    [Storable]
82    private RunCollection runs;
83    public RunCollection Runs {
84      get { return runs; }
85      private set {
86        if (value == null) throw new ArgumentNullException();
87        if (runs != value) {
88          if (runs != null) DeregisterRunsEvents();
89          runs = value;
90          if (runs != null) RegisterRunsEvents();
91        }
92      }
93    }
94
95    public IEnumerable<IOptimizer> NestedOptimizers {
96      get {
97        if (Optimizers == null) yield break;
98
99        foreach (IOptimizer opt in Optimizers) {
100          yield return opt;
101          foreach (IOptimizer nestedOpt in opt.NestedOptimizers)
102            yield return nestedOpt;
103        }
104      }
105    }
106
107    private bool experimentStarted = false;
108    private bool experimentStopped = false;
109    private readonly ManualResetEventSlim allOptimizerFinished = new ManualResetEventSlim(false); // this indicates that all started optimizers have been paused or stopped
110
111    public Experiment()
112      : base() {
113      name = ItemName;
114      description = ItemDescription;
115      executionState = ExecutionState.Stopped;
116      executionTime = TimeSpan.Zero;
117      optimizers = new OptimizerList();
118      Runs = new RunCollection { OptimizerName = Name };
119      Initialize();
120    }
121    public Experiment(string name)
122      : base(name) {
123      description = ItemDescription;
124      executionState = ExecutionState.Stopped;
125      executionTime = TimeSpan.Zero;
126      optimizers = new OptimizerList();
127      Runs = new RunCollection { OptimizerName = Name };
128      Initialize();
129    }
130    public Experiment(string name, string description)
131      : base(name, description) {
132      executionState = ExecutionState.Stopped;
133      executionTime = TimeSpan.Zero;
134      optimizers = new OptimizerList();
135      Runs = new RunCollection { OptimizerName = Name };
136      Initialize();
137    }
138    [StorableConstructor]
139    private Experiment(bool deserializing) : base(deserializing) { }
140    [StorableHook(HookType.AfterDeserialization)]
141    private void AfterDeserialization() {
142      Initialize();
143    }
144    private Experiment(Experiment original, Cloner cloner)
145      : base(original, cloner) {
146      executionState = original.executionState;
147      executionTime = original.executionTime;
148      optimizers = cloner.Clone(original.optimizers);
149      runs = cloner.Clone(original.runs);
150
151      experimentStarted = original.experimentStarted;
152      experimentStopped = original.experimentStopped;
153      Initialize();
154    }
155    public override IDeepCloneable Clone(Cloner cloner) {
156      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
157      return new Experiment(this, cloner);
158    }
159
160    private void Initialize() {
161      RegisterOptimizersEvents();
162      foreach (IOptimizer optimizer in optimizers)
163        RegisterOptimizerEvents(optimizer);
164      if (runs != null) RegisterRunsEvents();
165    }
166
167    public void Prepare() {
168      Prepare(false);
169    }
170    public void Prepare(bool clearRuns) {
171      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
172        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
173      if (Optimizers.Count == 0) return;
174
175      if (clearRuns) runs.Clear();
176
177      experimentStarted = false;
178      experimentStopped = false;
179      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState != ExecutionState.Started)) {
180        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
181        try { optimizer.Prepare(clearRuns); } catch (InvalidOperationException) { }
182      }
183    }
184    public void Start() {
185      Start(CancellationToken.None);
186    }
187    public void Start(CancellationToken cancellationToken) {
188      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
189        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
190      if (!Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) return;
191
192      experimentStarted = true;
193      experimentStopped = false;
194      allOptimizerFinished.Reset();
195      IOptimizer optimizer;
196      while ((optimizer = Optimizers.FirstOrDefault(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) != null) {
197        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
198        try { optimizer.Start(cancellationToken); } catch (InvalidOperationException) { }
199        if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
200      }
201      allOptimizerFinished.Wait();
202    }
203    public async Task StartAsync() { await StartAsync(CancellationToken.None); }
204    public async Task StartAsync(CancellationToken cancellationToken) {
205      await AsyncHelper.DoAsync(Start, cancellationToken);
206    }
207    public void Pause() {
208      if (ExecutionState != ExecutionState.Started)
209        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
210      if (Optimizers.Count == 0) return;
211
212      experimentStarted = false;
213      experimentStopped = false;
214      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
215        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
216        try { optimizer.Pause(); } catch (InvalidOperationException) { }
217      }
218    }
219    public void Stop() {
220      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
221        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
222      if (Optimizers.Count == 0) return;
223
224      experimentStarted = false;
225      experimentStopped = true;
226      if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
227        foreach (var optimizer in Optimizers.Where(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
228          // a race-condition may occur when the optimizer has changed the state by itself in the meantime
229          try { optimizer.Stop(); } catch (InvalidOperationException) { }
230        }
231      } else {
232        OnStopped();
233      }
234    }
235
236    #region Events
237    protected override void OnNameChanged() {
238      base.OnNameChanged();
239      Runs.OptimizerName = Name;
240    }
241
242    public event EventHandler ExecutionStateChanged;
243    private void OnExecutionStateChanged() {
244      EventHandler handler = ExecutionStateChanged;
245      if (handler != null) handler(this, EventArgs.Empty);
246    }
247    [Obsolete("deprecated needs to be removed")]
248    public event EventHandler ExecutionTimeChanged;
249    public event EventHandler Prepared;
250    private void OnPrepared() {
251      ExecutionState = ExecutionState.Prepared;
252      EventHandler handler = Prepared;
253      if (handler != null) handler(this, EventArgs.Empty);
254    }
255    public event EventHandler Started;
256    private void OnStarted() {
257      ExecutionState = ExecutionState.Started;
258      EventHandler handler = Started;
259      if (handler != null) handler(this, EventArgs.Empty);
260    }
261    public event EventHandler Paused;
262    private void OnPaused() {
263      ExecutionState = ExecutionState.Paused;
264      allOptimizerFinished.Set();
265      EventHandler handler = Paused;
266      if (handler != null) handler(this, EventArgs.Empty);
267    }
268    public event EventHandler Stopped;
269    private void OnStopped() {
270      ExecutionState = ExecutionState.Stopped;
271      allOptimizerFinished.Set();
272      EventHandler handler = Stopped;
273      if (handler != null) handler(this, EventArgs.Empty);
274    }
275    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
276    private void OnExceptionOccurred(Exception exception) {
277      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
278      if (handler != null) handler(this, new EventArgs<Exception>(exception));
279    }
280
281    private void RegisterOptimizersEvents() {
282      Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
283      Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
284      Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
285      Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
286    }
287    private void DeregisterOptimizersEvents() {
288      Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
289      Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
290      Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
291      Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
292    }
293    private void Optimizers_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
294      foreach (IndexedItem<IOptimizer> item in e.OldItems)
295        RemoveOptimizer(item.Value);
296      foreach (IndexedItem<IOptimizer> item in e.Items)
297        AddOptimizer(item.Value);
298    }
299    private void Optimizers_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
300      foreach (IndexedItem<IOptimizer> item in e.Items)
301        AddOptimizer(item.Value);
302    }
303    private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
304      foreach (IndexedItem<IOptimizer> item in e.Items)
305        RemoveOptimizer(item.Value);
306    }
307    private void Optimizers_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
308      foreach (IndexedItem<IOptimizer> item in e.OldItems)
309        RemoveOptimizer(item.Value);
310      foreach (IndexedItem<IOptimizer> item in e.Items)
311        AddOptimizer(item.Value);
312    }
313    private void AddOptimizer(IOptimizer optimizer) {
314      RegisterOptimizerEvents(optimizer);
315      Runs.AddRange(optimizer.Runs);
316      optimizer.Prepare();
317      if (ExecutionState == ExecutionState.Stopped && optimizer.ExecutionState == ExecutionState.Prepared)
318        OnPrepared();
319    }
320    private void RemoveOptimizer(IOptimizer optimizer) {
321      DeregisterOptimizerEvents(optimizer);
322      Runs.RemoveRange(optimizer.Runs);
323      if (ExecutionState == ExecutionState.Prepared && !optimizers.Any(opt => opt.ExecutionState == ExecutionState.Prepared))
324        OnStopped();
325    }
326
327    private void RegisterOptimizerEvents(IOptimizer optimizer) {
328      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
329      optimizer.Paused += new EventHandler(optimizer_Paused);
330      optimizer.Prepared += new EventHandler(optimizer_Prepared);
331      optimizer.Started += new EventHandler(optimizer_Started);
332      optimizer.Stopped += new EventHandler(optimizer_Stopped);
333      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
334      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
335      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
336    }
337    private void DeregisterOptimizerEvents(IOptimizer optimizer) {
338      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
339      optimizer.Paused -= new EventHandler(optimizer_Paused);
340      optimizer.Prepared -= new EventHandler(optimizer_Prepared);
341      optimizer.Started -= new EventHandler(optimizer_Started);
342      optimizer.Stopped -= new EventHandler(optimizer_Stopped);
343      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
344      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
345      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
346    }
347
348    private readonly object locker = new object();
349    private readonly object runsLocker = new object();
350    private void optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
351      lock (locker)
352        OnExceptionOccurred(e.Value);
353    }
354    private void optimizer_Paused(object sender, EventArgs e) {
355      lock (locker)
356        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
357    }
358    private void optimizer_Prepared(object sender, EventArgs e) {
359      lock (locker)
360        if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
361    }
362    private void optimizer_Started(object sender, EventArgs e) {
363      lock (locker)
364        if (ExecutionState != ExecutionState.Started) OnStarted();
365    }
366    private void optimizer_Stopped(object sender, EventArgs e) {
367      lock (locker) {
368        if (experimentStopped) {
369          if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) OnStopped();
370        } else {
371          if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) return;
372          else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) OnStopped();
373          else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) OnPaused();
374        }
375      }
376    }
377    private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
378      lock (runsLocker) {
379        Runs.RemoveRange(e.OldItems);
380        Runs.AddRange(e.Items);
381      }
382    }
383    private void optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
384      lock (runsLocker)
385        Runs.AddRange(e.Items);
386    }
387    private void optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
388      lock (runsLocker)
389        Runs.RemoveRange(e.Items);
390    }
391
392    private void RegisterRunsEvents() {
393      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
394      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
395    }
396    private void DeregisterRunsEvents() {
397      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
398      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
399    }
400    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
401      foreach (IOptimizer optimizer in Optimizers)
402        optimizer.Runs.RemoveRange(e.OldItems);
403    }
404    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
405      foreach (IOptimizer optimizer in Optimizers)
406        optimizer.Runs.RemoveRange(e.Items);
407    }
408    #endregion
409  }
410}
Note: See TracBrowser for help on using the repository browser.