Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs @ 16773

Last change on this file since 16773 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

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