Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GBT/HeuristicLab.Clients.Hive/3.3/HiveTasks/OptimizerHiveTask.cs @ 12448

Last change on this file since 12448 was 12041, checked in by ascheibe, 10 years ago

#2328 improved handling of batchruns in Hive

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