Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Async/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs @ 15287

Last change on this file since 15287 was 15281, checked in by abeham, 7 years ago

#2258: merged r14001:15280 from trunk into branch

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