Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Clients.Hive/3.3/HiveTasks/OptimizerHiveTask.cs @ 14927

Last change on this file since 14927 was 14927, checked in by gkronber, 7 years ago

#2520: changed all usages of StorableClass to use StorableType with an auto-generated GUID (did not add StorableType to other type definitions yet)

File size: 18.9 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.Linq;
25using HeuristicLab.Clients.Hive.Jobs;
26using HeuristicLab.Collections;
27using HeuristicLab.Common;
28using HeuristicLab.MainForm;
29using HeuristicLab.Optimization;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Clients.Hive {
33  public class OptimizerHiveTask : HiveTask<OptimizerTask> {
34    public Progress Progress { get; private set; }
35
36    #region Constructors and Cloning
37    public OptimizerHiveTask() {
38      Progress = new Progress();
39    }
40    public OptimizerHiveTask(IOptimizer optimizer)
41      : this() {
42      this.ItemTask = new OptimizerTask(optimizer);
43    }
44    public OptimizerHiveTask(OptimizerTask optimizerJob)
45      : this() {
46      this.ItemTask = optimizerJob;
47    }
48    protected OptimizerHiveTask(OptimizerHiveTask original, Cloner cloner)
49      : base(original, cloner) {
50      Progress = new Progress();
51    }
52    public override IDeepCloneable Clone(Cloner cloner) {
53      return new OptimizerHiveTask(this, cloner);
54    }
55    #endregion
56
57    /// <summary>
58    /// if this.Optimizer is an experiment
59    ///   Uses the child-optimizers of this.HiveTask and creates HiveTask-childs
60    /// if this.Optimizer is a batchrun
61    ///   Creates a number of child-jobs according to repetitions
62    /// </summary>
63    protected override void UpdateChildHiveTasks() {
64      base.UpdateChildHiveTasks();
65      childHiveTasksLock.EnterWriteLock();
66      try {
67        if (Task != null && syncTasksWithOptimizers) {
68          if (!ItemTask.ComputeInParallel) {
69            this.childHiveTasks.Clear();
70          } else {
71            if (ItemTask.Item is Optimization.Experiment) {
72              Optimization.Experiment experiment = (Optimization.Experiment)ItemTask.Item;
73              foreach (IOptimizer childOpt in experiment.Optimizers) {
74                var optimizerHiveTask = new OptimizerHiveTask(childOpt);
75                optimizerHiveTask.Task.Priority = Task.Priority; //inherit priority from parent
76                this.childHiveTasks.Add(optimizerHiveTask);
77              }
78            } else if (ItemTask.Item is Optimization.BatchRun) {
79              Optimization.BatchRun batchRun = ItemTask.OptimizerAsBatchRun;
80              if (batchRun.Optimizer != null) {
81                while (this.childHiveTasks.Count < batchRun.Repetitions) {
82                  var optimizerHiveTask = new OptimizerHiveTask(batchRun.Optimizer);
83                  optimizerHiveTask.Task.Priority = Task.Priority;
84                  this.childHiveTasks.Add(optimizerHiveTask);
85                }
86                while (this.childHiveTasks.Count > batchRun.Repetitions) {
87                  this.childHiveTasks.Remove(this.childHiveTasks.Last());
88                }
89              }
90            }
91          }
92        }
93      } finally {
94        childHiveTasksLock.ExitWriteLock();
95      }
96    }
97
98    protected override void RegisterItemTaskEvents() {
99      base.RegisterItemTaskEvents();
100      if (ItemTask != null) {
101        if (ItemTask.Item is Optimization.Experiment) {
102          Optimization.Experiment experiment = ItemTask.OptimizerAsExperiment;
103          experiment.Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
104          experiment.Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
105          experiment.Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
106          experiment.Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
107        } else if (ItemTask.Item is Optimization.BatchRun) {
108          Optimization.BatchRun batchRun = ItemTask.OptimizerAsBatchRun;
109          batchRun.RepetitionsChanged += new EventHandler(batchRun_RepetitionsChanged);
110          batchRun.OptimizerChanged += new EventHandler(batchRun_OptimizerChanged);
111        }
112      }
113    }
114    protected override void DeregisterItemTaskEvents() {
115      base.DeregisterItemTaskEvents();
116      if (ItemTask != null) {
117        if (ItemTask.Item is Optimization.Experiment) {
118          Optimization.Experiment experiment = ItemTask.OptimizerAsExperiment;
119          experiment.Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
120          experiment.Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
121          experiment.Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
122          experiment.Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
123        } else if (ItemTask.Item is Optimization.BatchRun) {
124          Optimization.BatchRun batchRun = ItemTask.OptimizerAsBatchRun;
125          batchRun.RepetitionsChanged -= new EventHandler(batchRun_RepetitionsChanged);
126          batchRun.OptimizerChanged -= new EventHandler(batchRun_OptimizerChanged);
127        }
128      }
129    }
130
131    private void batchRun_OptimizerChanged(object sender, EventArgs e) {
132      if (syncTasksWithOptimizers) {
133        UpdateChildHiveTasks();
134      }
135    }
136
137    private void batchRun_RepetitionsChanged(object sender, EventArgs e) {
138      if (syncTasksWithOptimizers) {
139        UpdateChildHiveTasks();
140      }
141    }
142
143    private void Optimizers_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
144      if (syncTasksWithOptimizers && this.ItemTask.ComputeInParallel) {
145        childHiveTasksLock.EnterWriteLock();
146        try {
147          foreach (var item in e.Items) {
148            if (GetChildByOptimizer(item.Value) == null && item.Value.Name != "Placeholder") {
149              this.childHiveTasks.Add(new OptimizerHiveTask(item.Value));
150            }
151          }
152        } finally { childHiveTasksLock.ExitWriteLock(); }
153      }
154    }
155    private void Optimizers_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
156      if (syncTasksWithOptimizers && this.ItemTask.ComputeInParallel) {
157        childHiveTasksLock.EnterWriteLock();
158        try {
159          foreach (var item in e.OldItems) {
160            this.childHiveTasks.Remove(this.GetChildByOptimizer(item.Value));
161          }
162          foreach (var item in e.Items) {
163            if (GetChildByOptimizer(item.Value) == null && item.Value.Name != "Placeholder") {
164              this.childHiveTasks.Add(new OptimizerHiveTask(item.Value));
165            }
166          }
167        } finally { childHiveTasksLock.ExitWriteLock(); }
168      }
169    }
170    private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
171      if (syncTasksWithOptimizers && this.ItemTask.ComputeInParallel) {
172        childHiveTasksLock.EnterWriteLock();
173        try {
174          foreach (var item in e.Items) {
175            this.childHiveTasks.Remove(this.GetChildByOptimizer(item.Value));
176          }
177        } finally { childHiveTasksLock.ExitWriteLock(); }
178      }
179    }
180    private void Optimizers_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
181      if (syncTasksWithOptimizers && this.ItemTask.ComputeInParallel) {
182        childHiveTasksLock.EnterWriteLock();
183        try {
184          foreach (var item in e.Items) {
185            this.childHiveTasks.Remove(this.GetChildByOptimizer(item.Value));
186          }
187        } finally { childHiveTasksLock.ExitWriteLock(); }
188      }
189    }
190
191    /// <summary>
192    /// if this.Optimizer is Experiment
193    ///   replace the child-optimizer in the experiment
194    /// if this.Optimizer is BatchRun
195    ///   add the runs from the optimizerTask to the batchrun and replace the Optimizer
196    /// </summary>
197    public override void IntegrateChild(ItemTask task, Guid childTaskId) {
198      var optimizerTask = (OptimizerTask)task;
199      syncTasksWithOptimizers = false; // don't sync with optimizers during this method
200
201      if (this.ItemTask != null && this.ItemTask.Item != null) {
202        if (this.ItemTask.Item is Optimization.Experiment) {
203          UpdateOptimizerInExperiment(this.ItemTask.OptimizerAsExperiment, optimizerTask);
204        } else if (this.ItemTask.Item is Optimization.BatchRun) {
205          UpdateOptimizerInBatchRun(this.ItemTask.OptimizerAsBatchRun, optimizerTask);
206        }
207      }
208
209      IEnumerable<HiveTask> childs = this.ChildHiveTasks.Where(j => j.Task.Id == childTaskId);
210      //TODO: in very rare cases childs is empty. This shouldn't be the case and should be further investigated.
211      if (childs.Count() > 0) {
212        OptimizerHiveTask child = childs.First() as OptimizerHiveTask;
213
214        if (child != null && !optimizerTask.ComputeInParallel) {
215          child.syncTasksWithOptimizers = false;
216          child.ItemTask = optimizerTask;
217          child.syncTasksWithOptimizers = true;
218        }
219      }
220
221      syncTasksWithOptimizers = true;
222    }
223
224    /// <summary>
225    /// Adds the runs from the optimizerTask to the batchrun and replaces the Optimizer
226    /// Sideeffect: the optimizerTask.Optimizer will be prepared (scopes are deleted and executionstate will be reset)
227    /// </summary>
228    private void UpdateOptimizerInBatchRun(BatchRun batchRun, OptimizerTask optimizerTask) {
229      itemTaskLock.EnterWriteLock();
230      try {
231        if (optimizerTask.Item is IAlgorithm) {
232          // only set the first optimizer as Optimizer. if every time the Optimizer would be set, the runs would be cleared each time
233          if (batchRun.Optimizer == null) {
234            batchRun.Optimizer = (IOptimizer)optimizerTask.Item.Clone();
235            batchRun.Optimizer.Runs.Clear();
236          }
237
238          foreach (IRun run in optimizerTask.Item.Runs) {
239            run.Name = GetNewRunName(run, batchRun.Runs);
240            batchRun.Optimizer.Runs.Add(run);
241          }
242        } else {
243          // only set the first optimizer as Optimizer. if every time the Optimizer would be set, the runs would be cleared each time
244          if (batchRun.Optimizer == null) {
245            batchRun.Optimizer = optimizerTask.Item;
246          }
247          foreach (IRun run in optimizerTask.Item.Runs) {
248            if (batchRun.Runs.Contains(run)) continue;
249            run.Name = GetNewRunName(run, batchRun.Runs);
250            batchRun.Runs.Add(run);
251          }
252        }
253      } finally {
254        itemTaskLock.ExitWriteLock();
255      }
256    }
257
258    /// <summary>
259    /// replace the child-optimizer in the experiment
260    /// Sideeffect: the optimizerTask.Optimizer will be prepared (scopes are deleted and executionstate will be reset)
261    /// </summary>
262    private void UpdateOptimizerInExperiment(Optimization.Experiment experiment, OptimizerTask optimizerTask) {
263      itemTaskLock.EnterWriteLock();
264      try {
265        if (optimizerTask.IndexInParentOptimizerList < 0)
266          throw new IndexOutOfRangeException("IndexInParentOptimizerList must be equal or greater than zero! The Task is invalid and the optimizer-tree cannot be reassembled.");
267
268        while (experiment.Optimizers.Count < optimizerTask.IndexInParentOptimizerList) {
269          experiment.Optimizers.Add(new UserDefinedAlgorithm("Placeholder")); // add dummy-entries to Optimizers so that its possible to insert the optimizerTask at the correct position
270        }
271        if (experiment.Optimizers.Count < optimizerTask.IndexInParentOptimizerList + 1) {
272          experiment.Optimizers.Add(optimizerTask.Item);
273        } else {
274          // if ComputeInParallel==true, don't replace the optimizer (except it is still a Placeholder)
275          // this is because Jobs with ComputeInParallel get submitted to hive with their child-optimizers deleted
276          if (!optimizerTask.ComputeInParallel || experiment.Optimizers[optimizerTask.IndexInParentOptimizerList].Name == "Placeholder") {
277            experiment.Optimizers[optimizerTask.IndexInParentOptimizerList] = optimizerTask.Item;
278          }
279        }
280      } finally {
281        itemTaskLock.ExitWriteLock();
282      }
283    }
284
285    /// <summary>
286    /// Sets the IndexInParentOptimizerList property of the OptimizerJob
287    /// according to the position in the OptimizerList of the parentHiveTask.Task
288    /// Recursively updates all the child-jobs as well
289    /// </summary>
290    internal void SetIndexInParentOptimizerList(OptimizerHiveTask parentHiveTask) {
291      if (parentHiveTask != null) {
292        if (parentHiveTask.ItemTask.Item is Optimization.Experiment) {
293          this.ItemTask.IndexInParentOptimizerList = parentHiveTask.ItemTask.OptimizerAsExperiment.Optimizers.IndexOf(this.ItemTask.Item);
294        } else if (parentHiveTask.ItemTask.Item is Optimization.BatchRun) {
295          this.ItemTask.IndexInParentOptimizerList = 0;
296        } else {
297          throw new NotSupportedException("Only Experiment and BatchRuns are supported");
298        }
299      }
300      childHiveTasksLock.EnterReadLock();
301      try {
302        foreach (OptimizerHiveTask child in childHiveTasks) {
303          child.SetIndexInParentOptimizerList(this);
304        }
305      } finally { childHiveTasksLock.ExitReadLock(); }
306    }
307
308    public override void AddChildHiveTask(HiveTask hiveTask) {
309      base.AddChildHiveTask(hiveTask);
310      var optimizerHiveJob = (OptimizerHiveTask)hiveTask;
311      syncTasksWithOptimizers = false;
312      if (this.ItemTask != null && optimizerHiveJob.ItemTask != null) {
313        // if task is in state Paused, it has to preserve its ResultCollection, which is cleared when a optimizer is added to an experiment
314        OptimizerTask optimizerJobClone = null;
315        if (optimizerHiveJob.Task.State == TaskState.Paused) {
316          optimizerJobClone = (OptimizerTask)optimizerHiveJob.ItemTask.Clone();
317        }
318
319        if (this.ItemTask.Item is Optimization.Experiment) {
320          if (!this.ItemTask.OptimizerAsExperiment.Optimizers.Contains(optimizerHiveJob.ItemTask.Item)) {
321            UpdateOptimizerInExperiment(this.ItemTask.OptimizerAsExperiment, optimizerHiveJob.ItemTask);
322          }
323        } else if (this.ItemTask.Item is Optimization.BatchRun) {
324          UpdateOptimizerInBatchRun(this.ItemTask.OptimizerAsBatchRun, optimizerHiveJob.ItemTask);
325        }
326
327        if (optimizerHiveJob.Task.State == TaskState.Paused) {
328          optimizerHiveJob.ItemTask = optimizerJobClone;
329        }
330      }
331      syncTasksWithOptimizers = true;
332    }
333
334    /// <summary>
335    /// Creates a TaskData object containing the Task and the IJob-Object as byte[]
336    /// </summary>
337    /// <param name="withoutChildOptimizers">
338    ///   if true the Child-Optimizers will not be serialized (if the task contains an Experiment)
339    /// </param>
340    public override TaskData GetAsTaskData(bool withoutChildOptimizers, out List<IPluginDescription> plugins) {
341      if (ItemTask == null) {
342        plugins = new List<IPluginDescription>();
343        return null;
344      }
345
346      IEnumerable<Type> usedTypes;
347      byte[] jobByteArray;
348      if (withoutChildOptimizers && ItemTask.Item is Optimization.Experiment) {
349        OptimizerTask clonedJob = (OptimizerTask)ItemTask.Clone(); // use a cloned task, so that the childHiveJob don't get confused
350        clonedJob.OptimizerAsExperiment.Optimizers.Clear();
351        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
352      } else if (withoutChildOptimizers && ItemTask.Item is Optimization.BatchRun) {
353        OptimizerTask clonedJob = (OptimizerTask)ItemTask.Clone();
354        clonedJob.OptimizerAsBatchRun.Optimizer = null;
355        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
356      } else if (ItemTask.Item is IAlgorithm) {
357        ((IAlgorithm)ItemTask.Item).StoreAlgorithmInEachRun = false; // avoid storing the algorithm in runs to reduce size
358        jobByteArray = PersistenceUtil.Serialize(ItemTask, out usedTypes);
359      } else {
360        jobByteArray = PersistenceUtil.Serialize(ItemTask, out usedTypes);
361      }
362
363      TaskData jobData = new TaskData() { TaskId = task.Id, Data = jobByteArray };
364      plugins = PluginUtil.GetPluginsForTask(usedTypes, ItemTask);
365      return jobData;
366    }
367
368    public OptimizerHiveTask GetChildByOptimizerTask(OptimizerTask optimizerTask) {
369      childHiveTasksLock.EnterReadLock();
370      try {
371        foreach (OptimizerHiveTask child in childHiveTasks) {
372          if (child.ItemTask == optimizerTask)
373            return child;
374        }
375        return null;
376      } finally { childHiveTasksLock.ExitReadLock(); }
377    }
378
379    public HiveTask<OptimizerTask> GetChildByOptimizer(IOptimizer optimizer) {
380      childHiveTasksLock.EnterReadLock();
381      try {
382        foreach (OptimizerHiveTask child in childHiveTasks) {
383          if (child.ItemTask.Item == optimizer)
384            return child;
385        }
386        return null;
387      } finally { childHiveTasksLock.ExitReadLock(); }
388    }
389
390    public void ExecuteReadActionOnItemTask(Action action) {
391      itemTaskLock.EnterReadLock();
392      try {
393        action();
394      } finally {
395        itemTaskLock.ExitReadLock();
396      }
397    }
398
399    #region Helpers
400    /// <summary>
401    /// Parses the run numbers out of runs and renames the run to the next number
402    /// </summary>
403    private static string GetNewRunName(IRun run, RunCollection runs) {
404      int idx = run.Name.IndexOf("Run ") + 4;
405
406      if (idx == 3 || runs.Count == 0)
407        return run.Name;
408
409      int maxRunNumber = int.MinValue;
410      foreach (IRun r in runs) {
411        int number = GetRunNumber(r.Name);
412        maxRunNumber = Math.Max(maxRunNumber, number);
413      }
414
415      return run.Name.Substring(0, idx) + (maxRunNumber + 1).ToString();
416    }
417
418    /// <summary>
419    /// Parses the number of a Run out of its name. Example "Genetic Algorithm Run 3" -> 3
420    /// </summary>
421    private static int GetRunNumber(string runName) {
422      int idx = runName.IndexOf("Run ") + 4;
423      if (idx == 3) {
424        return 0;
425      } else {
426        return int.Parse(runName.Substring(idx, runName.Length - idx));
427      }
428    }
429    #endregion
430  }
431}
Note: See TracBrowser for help on using the repository browser.