source: branches/HeuristicLab.GoalSeekingProblem/HeuristicLab.GoalSeekingProblem/3.4/GoalSeekingOptimizer.cs @ 14383

Last change on this file since 14383 was 14383, checked in by bburlacu, 4 years ago

#2679: Sync outer and inner optimizer states (fix pause/resume and stop issues).

File size: 13.8 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 HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Optimization;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using HeuristicLab.Problems.DataAnalysis;
31
32namespace HeuristicLab.GoalSeeking {
33  internal enum GoalSeekingOptimizerAction { None, Prepare, Start, Stop, Pause }
34
35  [StorableClass]
36  [Item("GoalSeeking Optimizer", "A wrapper for the GoalSeekingProblem class to facilitate adding models and problem data.")]
37  [Creatable("Algorithms")]
38  public class GoalSeekingOptimizer : NamedItem, IOptimizer, IStorableContent {
39    [Storable]
40    private IGoalSeekingProblem problem;
41    public IGoalSeekingProblem Problem {
42      get { return problem; }
43      set {
44        if (value == null || value == problem)
45          return;
46
47        problem = value;
48        // the problem takes precedence over the algorithm. if the algorithm is unsuitable we remove it.
49        if (optimizer != null && !optimizer.ProblemType.IsInstanceOfType(problem)) {
50          optimizer = null;
51          OnAlgorithmChanged();
52        }
53        if (optimizer != null)
54          optimizer.Problem = problem;
55      }
56    }
57
58    [Storable]
59    private IAlgorithm optimizer;
60    public IAlgorithm Optimizer {
61      get { return optimizer; }
62      set {
63        if (value == null || value == optimizer)
64          return;
65
66        // make sure the algorithm is suitable for the problem.
67        if (problem != null && !value.ProblemType.IsInstanceOfType(problem))
68          throw new InvalidOperationException("The algorithm is incompatible with the problem.");
69
70        optimizer = value;
71        optimizer.Problem = problem;
72        RegisterOptimizerEvents();
73        OnAlgorithmChanged();
74      }
75    }
76
77    [Storable]
78    private IRegressionProblemData problemData;
79    public IRegressionProblemData ProblemData {
80      get { return problemData; }
81      set {
82        if (value == null || value == problemData)
83          return;
84
85        if (problem == null)
86          throw new InvalidOperationException("Cannot set problem data. Please configure a problem first.");
87
88        problemData = value;
89        problem.Configure(problemData, problemData.TrainingIndices.First());
90        OnProblemDataChanged();
91      }
92    }
93
94    private GoalSeekingOptimizerAction gsoAction;
95
96    public GoalSeekingOptimizer() {
97      Name = "Goal Seeking Optimizer";
98    }
99
100    [StorableConstructor]
101    protected GoalSeekingOptimizer(bool deserializing) : base(deserializing) { }
102
103
104    [StorableHook(HookType.AfterDeserialization)]
105    private void AfterDeserialization() {
106      if (optimizer != null)
107        RegisterOptimizerEvents();
108    }
109
110    protected GoalSeekingOptimizer(GoalSeekingOptimizer original, Cloner cloner) : base(original, cloner) {
111      this.Optimizer = (IAlgorithm)original.Optimizer.Clone(cloner);
112      this.Problem = (IGoalSeekingProblem)original.Problem.Clone(cloner);
113      this.ProblemData = (IRegressionProblemData)original.ProblemData.Clone(cloner);
114    }
115
116    public override IDeepCloneable Clone(Cloner cloner) {
117      return new GoalSeekingOptimizer(this, cloner);
118    }
119
120    public EventHandler ProblemChanged;
121    private void OnProblemChanged() {
122      var changed = ProblemChanged;
123      if (changed != null)
124        changed(this, EventArgs.Empty);
125    }
126
127    public EventHandler AlgorithmChanged;
128    private void OnAlgorithmChanged() {
129      var changed = AlgorithmChanged;
130      if (changed != null)
131        changed(this, EventArgs.Empty);
132    }
133
134    public EventHandler ProblemDataChanged;
135    private void OnProblemDataChanged() {
136      var changed = ProblemDataChanged;
137      if (changed != null)
138        changed(this, EventArgs.Empty);
139    }
140
141    private int calculatedRows;
142    public void Start() {
143      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
144        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
145      if (optimizer == null) return;
146      gsoAction = GoalSeekingOptimizerAction.Start;
147      if (Optimizer.ExecutionState == ExecutionState.Stopped) {
148        Optimizer.Prepare(clearRuns: true);
149        calculatedRows = 0;
150
151        var row = problemData.TrainingIndices.Skip(calculatedRows).First();
152        problem.Configure(problemData, row);
153        optimizer.Prepare();
154      }
155      optimizer.Start();
156    }
157
158    public void Pause() {
159      if (ExecutionState != ExecutionState.Started)
160        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
161      if (optimizer == null) return;
162      gsoAction = GoalSeekingOptimizerAction.Pause;
163      if (optimizer.ExecutionState != ExecutionState.Started) return;
164      // a race-condition may occur when the algorithm has changed the state by itself in the meantime
165      try { optimizer.Pause(); }
166      catch (InvalidOperationException) { }
167    }
168
169    public void Stop() {
170      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
171        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
172      if (optimizer == null) return;
173      gsoAction = GoalSeekingOptimizerAction.Stop;
174      if (optimizer.ExecutionState != ExecutionState.Started && optimizer.ExecutionState != ExecutionState.Paused) {
175        OnStopped();
176        return;
177      }
178      // a race-condition may occur when the algorithm has changed the state by itself in the meantime
179      try { optimizer.Stop(); }
180      catch (InvalidOperationException) { }
181    }
182
183    public void Prepare() {
184      Prepare(false);
185    }
186
187    public void Prepare(bool clearRuns) {
188      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
189        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
190      if (optimizer != null) {
191        ExecutionTime = TimeSpan.Zero;
192        if (clearRuns) optimizer.Runs.Clear();
193        gsoAction = GoalSeekingOptimizerAction.Prepare;
194        // a race-condition may occur when the algorithm has changed the state by itself in the meantime
195        try { optimizer.Prepare(clearRuns); }
196        catch (InvalidOperationException) { }
197      } else {
198        ExecutionState = ExecutionState.Stopped;
199      }
200    }
201
202    [Storable]
203    private TimeSpan executionTime;
204    public TimeSpan ExecutionTime {
205      get {
206        if ((Optimizer != null) && (Optimizer.ExecutionState != ExecutionState.Stopped))
207          return executionTime + Optimizer.ExecutionTime;
208        else
209          return executionTime;
210      }
211      private set {
212        executionTime = value;
213        OnExecutionTimeChanged();
214      }
215    }
216
217    public RunCollection Runs {
218      get {
219        if (optimizer == null)
220          return new RunCollection(); // return an empty run collection
221        return Optimizer.Runs;
222      }
223    }
224
225    public IEnumerable<IOptimizer> NestedOptimizers { get; }
226
227    public string Filename { get; set; }
228
229    public new static Image StaticItemImage {
230      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
231    }
232    public override Image ItemImage {
233      get {
234        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPrepared;
235        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStarted;
236        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPaused;
237        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStopped;
238        else return base.ItemImage;
239      }
240    }
241
242    #region Events
243    protected override void OnNameChanged() {
244      base.OnNameChanged();
245    }
246
247    #region event firing
248    public ExecutionState ExecutionState { get; private set; }
249    public event EventHandler ExecutionStateChanged;
250    private void OnExecutionStateChanged() {
251      EventHandler handler = ExecutionStateChanged;
252      if (handler != null) handler(this, EventArgs.Empty);
253    }
254
255    public event EventHandler ExecutionTimeChanged;
256    private void OnExecutionTimeChanged() {
257      EventHandler handler = ExecutionTimeChanged;
258      if (handler != null) handler(this, EventArgs.Empty);
259    }
260
261    public event EventHandler Prepared;
262    private void OnPrepared() {
263      gsoAction = GoalSeekingOptimizerAction.None;
264      ExecutionState = ExecutionState.Prepared;
265      EventHandler handler = Prepared;
266      if (handler != null) handler(this, EventArgs.Empty);
267    }
268
269    public event EventHandler Started;
270    private void OnStarted() {
271      ExecutionState = ExecutionState.Started;
272      EventHandler handler = Started;
273      if (handler != null) handler(this, EventArgs.Empty);
274    }
275
276    public event EventHandler Paused;
277    private void OnPaused() {
278      gsoAction = GoalSeekingOptimizerAction.None;
279      ExecutionState = ExecutionState.Paused;
280      EventHandler handler = Paused;
281      if (handler != null) handler(this, EventArgs.Empty);
282    }
283
284    public event EventHandler Stopped;
285    private void OnStopped() {
286      gsoAction = GoalSeekingOptimizerAction.None;
287      ExecutionState = ExecutionState.Stopped;
288      EventHandler handler = Stopped;
289      if (handler != null) handler(this, EventArgs.Empty);
290    }
291
292    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
293    private void OnExceptionOccurred(Exception exception) {
294      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
295      if (handler != null) handler(this, new EventArgs<Exception>(exception));
296    }
297
298    public event EventHandler OptimizerChanged;
299    private void OnOptimizerChanged() {
300      EventHandler handler = OptimizerChanged;
301      if (handler != null) handler(this, EventArgs.Empty);
302    }
303
304    public event EventHandler RepetitionsChanged;
305    private void OnRepetitionsChanged() {
306      EventHandler handler = RepetitionsChanged;
307      if (handler != null) handler(this, EventArgs.Empty);
308    }
309
310    public event EventHandler RepetetionsCounterChanged;
311    private void OnRepetitionsCounterChanged() {
312      EventHandler handler = RepetetionsCounterChanged;
313      if (handler != null) handler(this, EventArgs.Empty);
314    }
315    #endregion
316
317    #region optimizer event handlers
318    private void RegisterOptimizerEvents() {
319      optimizer.ExceptionOccurred += Optimizer_ExceptionOccurred;
320      optimizer.ExecutionTimeChanged += Optimizer_ExecutionTimeChanged;
321      optimizer.Paused += Optimizer_Paused;
322      optimizer.Prepared += Optimizer_Prepared;
323      optimizer.Started += Optimizer_Started;
324      optimizer.Stopped += Optimizer_Stopped;
325    }
326
327    private void DeregisterOptimizerEvents() {
328      optimizer.ExceptionOccurred -= Optimizer_ExceptionOccurred;
329      optimizer.ExecutionTimeChanged -= Optimizer_ExecutionTimeChanged;
330      optimizer.Paused -= Optimizer_Paused;
331      optimizer.Prepared -= Optimizer_Prepared;
332      optimizer.Started -= Optimizer_Started;
333      optimizer.Stopped -= Optimizer_Stopped;
334    }
335
336    private void Optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
337      OnExceptionOccurred(e.Value);
338    }
339
340    private void Optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
341      OnExecutionTimeChanged();
342    }
343
344    private void Optimizer_Paused(object sender, EventArgs e) {
345      if (ExecutionState == ExecutionState.Started) {
346        OnPaused();
347      }
348    }
349
350    private void Optimizer_Prepared(object sender, EventArgs e) {
351      if (gsoAction == GoalSeekingOptimizerAction.Prepare || ExecutionState == ExecutionState.Stopped) {
352        calculatedRows = 0;
353        ExecutionTime = TimeSpan.Zero;
354        OnPrepared();
355      }
356    }
357
358    private void Optimizer_Started(object sender, EventArgs e) {
359      if (ExecutionState != ExecutionState.Started) {
360        OnStarted();
361      }
362    }
363
364    private void Optimizer_Stopped(object sender, EventArgs e) {
365      calculatedRows++;
366      ExecutionTime += optimizer.ExecutionTime;
367      var remainingRows = problemData.TrainingIndices.Skip(calculatedRows);
368
369      if (gsoAction == GoalSeekingOptimizerAction.Stop) OnStopped();
370      else if (!remainingRows.Any()) OnStopped();
371      else if (gsoAction == GoalSeekingOptimizerAction.Pause) OnPaused();
372      else if (gsoAction == GoalSeekingOptimizerAction.Start) {
373        var row = remainingRows.First();
374        problem.Configure(problemData, row);
375        optimizer.Prepare();
376        optimizer.Start();
377      } else if (ExecutionState == ExecutionState.Started) {
378        OnPaused();
379      } else OnStopped();
380    }
381    #endregion
382    #endregion
383  }
384}
Note: See TracBrowser for help on using the repository browser.