source: branches/2994-AutoDiffForIntervals/HeuristicLab.Clients.Hive/3.3/HiveTasks/OptimizerHiveTask.cs @ 17209

Last change on this file since 17209 was 17209, checked in by gkronber, 4 months ago

#2994: merged r17132:17198 from trunk to branch

File size: 18.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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 optimizerHiveTask = (OptimizerHiveTask)hiveTask;
319      syncTasksWithOptimizers = false;
320      if (this.ItemTask != null && optimizerHiveTask.ItemTask != null) {
321        OptimizerTask optimizerTaskClone = (OptimizerTask)optimizerHiveTask.ItemTask.Clone();
322
323        if (this.ItemTask.Item is Optimization.Experiment) {
324          if (!this.ItemTask.OptimizerAsExperiment.Optimizers.Contains(optimizerHiveTask.ItemTask.Item)) {
325            UpdateOptimizerInExperiment(this.ItemTask.OptimizerAsExperiment, optimizerHiveTask.ItemTask);
326          }
327        } else if (this.ItemTask.Item is Optimization.BatchRun) {
328          UpdateOptimizerInBatchRun(this.ItemTask.OptimizerAsBatchRun, optimizerHiveTask.ItemTask);
329        }
330
331        optimizerHiveTask.syncTasksWithOptimizers = false;
332        optimizerHiveTask.ItemTask = optimizerTaskClone;
333        optimizerHiveTask.syncTasksWithOptimizers = true;
334      }
335      syncTasksWithOptimizers = true;
336    }
337
338    /// <summary>
339    /// Creates a TaskData object containing the Task and the IJob-Object as byte[]
340    /// </summary>
341    /// <param name="withoutChildOptimizers">
342    ///   if true the Child-Optimizers will not be serialized (if the task contains an Experiment)
343    /// </param>
344    public override TaskData GetAsTaskData(bool withoutChildOptimizers, out List<IPluginDescription> plugins) {
345      if (ItemTask == null) {
346        plugins = new List<IPluginDescription>();
347        return null;
348      }
349
350      IEnumerable<Type> usedTypes;
351      byte[] jobByteArray;
352      if (withoutChildOptimizers && ItemTask.Item is Optimization.Experiment) {
353        OptimizerTask clonedJob = (OptimizerTask)ItemTask.Clone(); // use a cloned task, so that the childHiveJob don't get confused
354        clonedJob.OptimizerAsExperiment.Optimizers.Clear();
355        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
356      } else if (withoutChildOptimizers && ItemTask.Item is Optimization.BatchRun) {
357        OptimizerTask clonedJob = (OptimizerTask)ItemTask.Clone();
358        clonedJob.OptimizerAsBatchRun.Optimizer = null;
359        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
360      } else if (ItemTask.Item is IAlgorithm) {
361        ((IAlgorithm)ItemTask.Item).StoreAlgorithmInEachRun = false; // avoid storing the algorithm in runs to reduce size
362        jobByteArray = PersistenceUtil.Serialize(ItemTask, out usedTypes);
363      } else {
364        jobByteArray = PersistenceUtil.Serialize(ItemTask, out usedTypes);
365      }
366
367      TaskData jobData = new TaskData() { TaskId = task.Id, Data = jobByteArray };
368      plugins = PluginUtil.GetPluginsForTask(usedTypes, ItemTask);
369      return jobData;
370    }
371
372    public OptimizerHiveTask GetChildByOptimizerTask(OptimizerTask optimizerTask) {
373      childHiveTasksLock.EnterReadLock();
374      try {
375        foreach (OptimizerHiveTask child in childHiveTasks) {
376          if (child.ItemTask == optimizerTask)
377            return child;
378        }
379        return null;
380      }
381      finally { childHiveTasksLock.ExitReadLock(); }
382    }
383
384    public HiveTask<OptimizerTask> GetChildByOptimizer(IOptimizer optimizer) {
385      childHiveTasksLock.EnterReadLock();
386      try {
387        foreach (OptimizerHiveTask child in childHiveTasks) {
388          if (child.ItemTask.Item == optimizer)
389            return child;
390        }
391        return null;
392      }
393      finally { childHiveTasksLock.ExitReadLock(); }
394    }
395
396    public void ExecuteReadActionOnItemTask(Action action) {
397      itemTaskLock.EnterReadLock();
398      try {
399        action();
400      }
401      finally {
402        itemTaskLock.ExitReadLock();
403      }
404    }
405
406    #region Helpers
407    /// <summary>
408    /// Parses the run numbers out of runs and renames the run to the next number
409    /// </summary>
410    private static string GetNewRunName(IRun run, RunCollection runs) {
411      int idx = run.Name.IndexOf("Run ") + 4;
412
413      if (idx == 3 || runs.Count == 0)
414        return run.Name;
415
416      int maxRunNumber = int.MinValue;
417      foreach (IRun r in runs) {
418        int number = GetRunNumber(r.Name);
419        maxRunNumber = Math.Max(maxRunNumber, number);
420      }
421
422      return run.Name.Substring(0, idx) + (maxRunNumber + 1).ToString();
423    }
424
425    /// <summary>
426    /// Parses the number of a Run out of its name. Example "Genetic Algorithm Run 3" -> 3
427    /// </summary>
428    private static int GetRunNumber(string runName) {
429      int idx = runName.IndexOf("Run ") + 4;
430      if (idx == 3) {
431        return 0;
432      } else {
433        return int.Parse(runName.Substring(idx, runName.Length - idx));
434      }
435    }
436    #endregion
437  }
438}
Note: See TracBrowser for help on using the repository browser.