Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs @ 15689

Last change on this file since 15689 was 15018, checked in by gkronber, 8 years ago

#2520 introduced StorableConstructorFlag type for StorableConstructors

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