Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Breadcrumbs/HeuristicLab.Clients.Hive/3.3/HiveTasks/OptimizerHiveTask.cs @ 12962

Last change on this file since 12962 was 11594, checked in by jkarder, 10 years ago

#2116: merged r10041-r11593 from trunk into branch

File size: 18.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 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 (batchRun.Optimizer == null) {
237          batchRun.Optimizer = (IOptimizer)optimizerTask.Item; // only set the first optimizer as Optimizer. if every time the Optimizer would be set, the runs would be cleared each time
238        }
239        foreach (IRun run in optimizerTask.Item.Runs) {
240          if (!batchRun.Runs.Contains(run)) {
241            run.Name = GetNewRunName(run, batchRun.Runs);
242            batchRun.Runs.Add(run);
243          }
244        }
245      }
246      finally {
247        itemTaskLock.ExitWriteLock();
248      }
249    }
250
251    /// <summary>
252    /// replace the child-optimizer in the experiment
253    /// Sideeffect: the optimizerTask.Optimizer will be prepared (scopes are deleted and executionstate will be reset)
254    /// </summary>
255    private void UpdateOptimizerInExperiment(Optimization.Experiment experiment, OptimizerTask optimizerTask) {
256      itemTaskLock.EnterWriteLock();
257      try {
258        if (optimizerTask.IndexInParentOptimizerList < 0)
259          throw new IndexOutOfRangeException("IndexInParentOptimizerList must be equal or greater than zero! The Task is invalid and the optimizer-tree cannot be reassembled.");
260
261        while (experiment.Optimizers.Count < optimizerTask.IndexInParentOptimizerList) {
262          experiment.Optimizers.Add(new UserDefinedAlgorithm("Placeholder")); // add dummy-entries to Optimizers so that its possible to insert the optimizerTask at the correct position
263        }
264        if (experiment.Optimizers.Count < optimizerTask.IndexInParentOptimizerList + 1) {
265          experiment.Optimizers.Add(optimizerTask.Item);
266        } else {
267          // if ComputeInParallel==true, don't replace the optimizer (except it is still a Placeholder)
268          // this is because Jobs with ComputeInParallel get submitted to hive with their child-optimizers deleted
269          if (!optimizerTask.ComputeInParallel || experiment.Optimizers[optimizerTask.IndexInParentOptimizerList].Name == "Placeholder") {
270            experiment.Optimizers[optimizerTask.IndexInParentOptimizerList] = optimizerTask.Item;
271          }
272        }
273      }
274      finally {
275        itemTaskLock.ExitWriteLock();
276      }
277    }
278
279    /// <summary>
280    /// Sets the IndexInParentOptimizerList property of the OptimizerJob
281    /// according to the position in the OptimizerList of the parentHiveTask.Task
282    /// Recursively updates all the child-jobs as well
283    /// </summary>
284    internal void SetIndexInParentOptimizerList(OptimizerHiveTask parentHiveTask) {
285      if (parentHiveTask != null) {
286        if (parentHiveTask.ItemTask.Item is Optimization.Experiment) {
287          this.ItemTask.IndexInParentOptimizerList = parentHiveTask.ItemTask.OptimizerAsExperiment.Optimizers.IndexOf(this.ItemTask.Item);
288        } else if (parentHiveTask.ItemTask.Item is Optimization.BatchRun) {
289          this.ItemTask.IndexInParentOptimizerList = 0;
290        } else {
291          throw new NotSupportedException("Only Experiment and BatchRuns are supported");
292        }
293      }
294      childHiveTasksLock.EnterReadLock();
295      try {
296        foreach (OptimizerHiveTask child in childHiveTasks) {
297          child.SetIndexInParentOptimizerList(this);
298        }
299      }
300      finally { childHiveTasksLock.ExitReadLock(); }
301    }
302
303    public override void AddChildHiveTask(HiveTask hiveTask) {
304      base.AddChildHiveTask(hiveTask);
305      var optimizerHiveJob = (OptimizerHiveTask)hiveTask;
306      syncTasksWithOptimizers = false;
307      if (this.ItemTask != null && optimizerHiveJob.ItemTask != null) {
308        // if task is in state Paused, it has to preserve its ResultCollection, which is cleared when a optimizer is added to an experiment
309        OptimizerTask optimizerJobClone = null;
310        if (optimizerHiveJob.Task.State == TaskState.Paused) {
311          optimizerJobClone = (OptimizerTask)optimizerHiveJob.ItemTask.Clone();
312        }
313
314        if (this.ItemTask.Item is Optimization.Experiment) {
315          if (!this.ItemTask.OptimizerAsExperiment.Optimizers.Contains(optimizerHiveJob.ItemTask.Item)) {
316            UpdateOptimizerInExperiment(this.ItemTask.OptimizerAsExperiment, optimizerHiveJob.ItemTask);
317          }
318        } else if (this.ItemTask.Item is Optimization.BatchRun) {
319          UpdateOptimizerInBatchRun(this.ItemTask.OptimizerAsBatchRun, optimizerHiveJob.ItemTask);
320        }
321
322        if (optimizerHiveJob.Task.State == TaskState.Paused) {
323          optimizerHiveJob.ItemTask = optimizerJobClone;
324        }
325      }
326      syncTasksWithOptimizers = true;
327    }
328
329    /// <summary>
330    /// Creates a TaskData object containing the Task and the IJob-Object as byte[]
331    /// </summary>
332    /// <param name="withoutChildOptimizers">
333    ///   if true the Child-Optimizers will not be serialized (if the task contains an Experiment)
334    /// </param>
335    public override TaskData GetAsTaskData(bool withoutChildOptimizers, out List<IPluginDescription> plugins) {
336      plugins = new List<IPluginDescription>();
337      if (this.itemTask == null) // || this.jobItem.Optimizer == null
338        return null;
339
340      IEnumerable<Type> usedTypes;
341      byte[] jobByteArray;
342      if (withoutChildOptimizers && this.ItemTask.Item is Optimization.Experiment) {
343        OptimizerTask clonedJob = (OptimizerTask)this.ItemTask.Clone(); // use a cloned task, so that the childHiveJob don't get confused
344        clonedJob.OptimizerAsExperiment.Optimizers.Clear();
345        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
346      } else if (withoutChildOptimizers && this.ItemTask.Item is Optimization.BatchRun) {
347        OptimizerTask clonedJob = (OptimizerTask)this.ItemTask.Clone();
348        clonedJob.OptimizerAsBatchRun.Optimizer = null;
349        jobByteArray = PersistenceUtil.Serialize(clonedJob, out usedTypes);
350      } else if (this.ItemTask.Item is IAlgorithm) {
351        ((IAlgorithm)this.ItemTask.Item).StoreAlgorithmInEachRun = false; // avoid storing the algorithm in runs to reduce size
352        jobByteArray = PersistenceUtil.Serialize(this.ItemTask, out usedTypes);
353      } else {
354        jobByteArray = PersistenceUtil.Serialize(this.ItemTask, out usedTypes);
355      }
356
357      TaskData jobData = new TaskData() { TaskId = task.Id, Data = jobByteArray };
358      PluginUtil.CollectDeclaringPlugins(plugins, usedTypes);
359      return jobData;
360    }
361
362    public OptimizerHiveTask GetChildByOptimizerTask(OptimizerTask optimizerTask) {
363      childHiveTasksLock.EnterReadLock();
364      try {
365        foreach (OptimizerHiveTask child in childHiveTasks) {
366          if (child.ItemTask == optimizerTask)
367            return child;
368        }
369        return null;
370      }
371      finally { childHiveTasksLock.ExitReadLock(); }
372    }
373
374    public HiveTask<OptimizerTask> GetChildByOptimizer(IOptimizer optimizer) {
375      childHiveTasksLock.EnterReadLock();
376      try {
377        foreach (OptimizerHiveTask child in childHiveTasks) {
378          if (child.ItemTask.Item == optimizer)
379            return child;
380        }
381        return null;
382      }
383      finally { childHiveTasksLock.ExitReadLock(); }
384    }
385
386    public void ExecuteReadActionOnItemTask(Action action) {
387      itemTaskLock.EnterReadLock();
388      try {
389        action();
390      }
391      finally {
392        itemTaskLock.ExitReadLock();
393      }
394    }
395
396    #region Helpers
397    /// <summary>
398    /// Parses the run numbers out of runs and renames the run to the next number
399    /// </summary>
400    private static string GetNewRunName(IRun run, RunCollection runs) {
401      int idx = run.Name.IndexOf("Run ") + 4;
402
403      if (idx == 3 || runs.Count == 0)
404        return run.Name;
405
406      int maxRunNumber = int.MinValue;
407      foreach (IRun r in runs) {
408        int number = GetRunNumber(r.Name);
409        maxRunNumber = Math.Max(maxRunNumber, number);
410      }
411
412      return run.Name.Substring(0, idx) + (maxRunNumber + 1).ToString();
413    }
414
415    /// <summary>
416    /// Parses the number of a Run out of its name. Example "Genetic Algorithm Run 3" -> 3
417    /// </summary>
418    private static int GetRunNumber(string runName) {
419      int idx = runName.IndexOf("Run ") + 4;
420      if (idx == 3) {
421        return 0;
422      } else {
423        return int.Parse(runName.Substring(idx, runName.Length - idx));
424      }
425    }
426    #endregion
427  }
428}
Note: See TracBrowser for help on using the repository browser.