source: stable/HeuristicLab.Optimization/3.3/RunCollection.cs @ 11522

Last change on this file since 11522 was 11522, checked in by abeham, 8 years ago

#2120: merged to stable

File size: 22.1 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.ComponentModel;
25using System.Linq;
26using HeuristicLab.Collections;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31
32namespace HeuristicLab.Optimization {
33  [Item("Run Collection", "Represents a collection of runs.")]
34  [Creatable("Testing & Analysis")]
35  [StorableClass]
36  public class RunCollection : ItemCollection<IRun>, IStringConvertibleMatrix, IStorableContent {
37    public string Filename { get; set; }
38
39    [StorableConstructor]
40    protected RunCollection(bool deserializing)
41      : base(deserializing) {
42      updateOfRunsInProgress = false;
43    }
44    protected RunCollection(RunCollection original, Cloner cloner)
45      : base(original, cloner) {
46      updateOfRunsInProgress = false;
47      optimizerName = original.optimizerName;
48
49      resultNames = new List<string>(original.resultNames);
50      parameterNames = new List<string>(original.parameterNames);
51      dataTypes = new Dictionary<string, HashSet<Type>>();
52      foreach (string s in original.dataTypes.Keys)
53        dataTypes[s] = new HashSet<Type>(original.dataTypes[s]);
54
55      constraints = new RunCollectionConstraintCollection(original.constraints.Select(x => cloner.Clone(x)));
56      modifiers = new CheckedItemList<IRunCollectionModifier>(original.modifiers.Select(cloner.Clone));
57      foreach (IRunCollectionConstraint constraint in constraints)
58        constraint.ConstrainedValue = this;
59      RegisterConstraintsEvents();
60      RegisterConstraintEvents(constraints);
61
62      UpdateFiltering(true);
63    }
64    public RunCollection() : base() { Initialize(); }
65    public RunCollection(int capacity) : base(capacity) { Initialize(); }
66    public RunCollection(IEnumerable<IRun> collection) : base(collection) { Initialize(); this.OnItemsAdded(collection); }
67    private void Initialize() {
68      updateOfRunsInProgress = false;
69      parameterNames = new List<string>();
70      resultNames = new List<string>();
71      dataTypes = new Dictionary<string, HashSet<Type>>();
72      constraints = new RunCollectionConstraintCollection();
73      modifiers = new CheckedItemList<IRunCollectionModifier>();
74      RegisterConstraintsEvents();
75    }
76
77    [Storable]
78    private Dictionary<string, HashSet<Type>> dataTypes;
79    public IEnumerable<Type> GetDataType(string columnName) {
80      if (!dataTypes.ContainsKey(columnName))
81        return new Type[0];
82      return dataTypes[columnName];
83    }
84
85    [Storable]
86    private RunCollectionConstraintCollection constraints;
87    public RunCollectionConstraintCollection Constraints {
88      get { return constraints; }
89    }
90
91    [Storable]
92    private CheckedItemList<IRunCollectionModifier> modifiers;
93    public CheckedItemList<IRunCollectionModifier> Modifiers {
94      get { return modifiers; }
95    }
96
97
98    private bool updateOfRunsInProgress;
99    public bool UpdateOfRunsInProgress {
100      get { return updateOfRunsInProgress; }
101      set {
102        if (updateOfRunsInProgress != value) {
103          updateOfRunsInProgress = value;
104          OnUpdateOfRunsInProgressChanged();
105        }
106      }
107    }
108
109    private string optimizerName = string.Empty;
110    [Storable]
111    public string OptimizerName {
112      get { return optimizerName; }
113      set {
114        if (value != optimizerName && !string.IsNullOrEmpty(value)) {
115          optimizerName = value;
116          OnOptimizerNameChanged();
117        }
118      }
119    }
120
121    // BackwardsCompatibility3.3
122    #region Backwards compatible code, remove with 3.4
123    [Storable(AllowOneWay = true)]
124    private string AlgorithmName {
125      set { optimizerName = value; }
126    }
127    #endregion
128
129    [StorableHook(HookType.AfterDeserialization)]
130    private void AfterDeserialization() {
131      if (constraints == null) constraints = new RunCollectionConstraintCollection();
132      if (modifiers == null) modifiers = new CheckedItemList<IRunCollectionModifier>();
133      RegisterConstraintsEvents();
134      RegisterConstraintEvents(constraints);
135      UpdateFiltering(true);
136    }
137
138    public override IDeepCloneable Clone(Cloner cloner) {
139      return new RunCollection(this, cloner);
140    }
141
142    public event EventHandler UpdateOfRunsInProgressChanged;
143    protected virtual void OnUpdateOfRunsInProgressChanged() {
144      var handler = UpdateOfRunsInProgressChanged;
145      if (handler != null) handler(this, EventArgs.Empty);
146    }
147
148    public event EventHandler OptimizerNameChanged;
149    protected virtual void OnOptimizerNameChanged() {
150      var handler = OptimizerNameChanged;
151      if (handler != null) handler(this, EventArgs.Empty);
152    }
153
154    protected override void OnCollectionReset(IEnumerable<IRun> items, IEnumerable<IRun> oldItems) {
155      parameterNames.Clear();
156      resultNames.Clear();
157      dataTypes.Clear();
158      foreach (IRun run in items) {
159        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
160          AddParameter(parameter.Key, parameter.Value);
161        foreach (KeyValuePair<string, IItem> result in run.Results)
162          AddResult(result.Key, result.Value);
163        run.PropertyChanged += RunOnPropertyChanged;
164        RegisterRunParametersEvents(run);
165        RegisterRunResultsEvents(run);
166      }
167      foreach (IRun run in oldItems) {
168        run.PropertyChanged -= RunOnPropertyChanged;
169        DeregisterRunParametersEvents(run);
170        DeregisterRunResultsEvents(run);
171      }
172      columnNameCache = null;
173      OnColumnsChanged();
174      OnColumnNamesChanged();
175      rowNamesCache = null;
176      base.OnCollectionReset(items, oldItems);
177      OnRowsChanged();
178      OnRowNamesChanged();
179      OnReset();
180      UpdateFiltering(false);
181    }
182    protected override void OnItemsAdded(IEnumerable<IRun> items) {
183      bool columnsChanged = false;
184      foreach (IRun run in items) {
185        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
186          columnsChanged |= AddParameter(parameter.Key, parameter.Value);
187        foreach (KeyValuePair<string, IItem> result in run.Results)
188          columnsChanged |= AddResult(result.Key, result.Value);
189        run.PropertyChanged += RunOnPropertyChanged;
190        RegisterRunParametersEvents(run);
191        RegisterRunResultsEvents(run);
192      }
193      if (columnsChanged) columnNameCache = null;
194      rowNamesCache = null;
195      base.OnItemsAdded(items);
196      OnReset();
197      OnRowsChanged();
198      OnRowNamesChanged();
199      if (columnsChanged) {
200        OnColumnsChanged();
201        OnColumnNamesChanged();
202      }
203      UpdateFiltering(false);
204    }
205    protected override void OnItemsRemoved(IEnumerable<IRun> items) {
206      bool columnsChanged = false;
207      foreach (IRun run in items) {
208        foreach (string parameterName in run.Parameters.Keys)
209          columnsChanged |= RemoveParameterName(parameterName);
210        foreach (string resultName in run.Results.Keys)
211          columnsChanged |= RemoveResultName(resultName);
212        run.PropertyChanged -= RunOnPropertyChanged;
213        DeregisterRunParametersEvents(run);
214        DeregisterRunResultsEvents(run);
215      }
216      if (columnsChanged) columnNameCache = null;
217      rowNamesCache = null;
218      base.OnItemsRemoved(items);
219      OnReset();
220      OnRowsChanged();
221      OnRowNamesChanged();
222      if (columnsChanged) {
223        OnColumnsChanged();
224        OnColumnNamesChanged();
225      }
226    }
227
228    private void RunOnPropertyChanged(object sender, PropertyChangedEventArgs e) {
229      if (e.PropertyName == "Parameters") {
230        RegisterRunParametersEvents((IRun)sender);
231      } else if (e.PropertyName == "Results") {
232        RegisterRunResultsEvents((IRun)sender);
233      }
234    }
235
236    private void RegisterRunParametersEvents(IRun run) {
237      IObservableDictionary<string, IItem> dict = run.Parameters;
238      dict.ItemsAdded += RunOnParameterChanged;
239      dict.ItemsRemoved += RunOnParameterRemoved;
240      dict.ItemsReplaced += RunOnParameterChanged;
241      dict.CollectionReset += RunOnParameterChanged;
242    }
243
244    private void RegisterRunResultsEvents(IRun run) {
245      IObservableDictionary<string, IItem> dict = run.Results;
246      dict.ItemsAdded += RunOnResultChanged;
247      dict.ItemsRemoved += RunOnResultRemoved;
248      dict.ItemsReplaced += RunOnResultChanged;
249      dict.CollectionReset += RunOnResultChanged;
250    }
251
252    private void DeregisterRunParametersEvents(IRun run) {
253      IObservableDictionary<string, IItem> dict = run.Parameters;
254      dict.ItemsAdded -= RunOnParameterChanged;
255      dict.ItemsRemoved -= RunOnParameterRemoved;
256      dict.ItemsReplaced -= RunOnParameterChanged;
257      dict.CollectionReset -= RunOnParameterChanged;
258    }
259
260    private void DeregisterRunResultsEvents(IRun run) {
261      IObservableDictionary<string, IItem> dict = run.Results;
262      dict.ItemsAdded -= RunOnResultChanged;
263      dict.ItemsRemoved -= RunOnResultRemoved;
264      dict.ItemsReplaced -= RunOnResultChanged;
265      dict.CollectionReset -= RunOnResultChanged;
266    }
267
268    private void RunOnParameterChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
269      bool columnsChanged = false;
270      foreach (var param in e.Items)
271        columnsChanged |= AddParameter(param.Key, param.Value);
272      foreach (var param in e.OldItems)
273        columnsChanged |= RemoveParameterName(param.Key);
274      if (columnsChanged) columnNameCache = null;
275      OnReset();
276      if (columnsChanged) {
277        OnColumnsChanged();
278        OnColumnNamesChanged();
279      }
280    }
281
282    private void RunOnParameterRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
283      bool columnsChanged = false;
284      foreach (var param in e.Items)
285        columnsChanged |= RemoveParameterName(param.Key);
286      if (columnsChanged) columnNameCache = null;
287      OnReset();
288      if (columnsChanged) {
289        OnColumnsChanged();
290        OnColumnNamesChanged();
291      }
292    }
293
294    private void RunOnResultChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
295      bool columnsChanged = false;
296      foreach (var result in e.Items)
297        columnsChanged |= AddResult(result.Key, result.Value);
298      foreach (var result in e.OldItems)
299        columnsChanged |= RemoveResultName(result.Key);
300      if (columnsChanged) columnNameCache = null;
301      OnReset();
302      if (columnsChanged) {
303        OnColumnsChanged();
304        OnColumnNamesChanged();
305      }
306    }
307
308    private void RunOnResultRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
309      bool columnsChanged = false;
310      foreach (var result in e.Items)
311        columnsChanged |= RemoveResultName(result.Key);
312      if (columnsChanged) columnNameCache = null;
313      OnReset();
314      if (columnsChanged) {
315        OnColumnsChanged();
316        OnColumnNamesChanged();
317      }
318    }
319
320    private bool AddParameter(string name, IItem value) {
321      if (value == null)
322        return false;
323      if (!parameterNames.Contains(name)) {
324        parameterNames.Add(name);
325        dataTypes[name] = new HashSet<Type>();
326        dataTypes[name].Add(value.GetType());
327        return true;
328      }
329      dataTypes[name].Add(value.GetType());
330      return false;
331    }
332    private bool AddResult(string name, IItem value) {
333      if (value == null)
334        return false;
335      if (!resultNames.Contains(name)) {
336        resultNames.Add(name);
337        dataTypes[name] = new HashSet<Type>();
338        dataTypes[name].Add(value.GetType());
339        return true;
340      }
341      dataTypes[name].Add(value.GetType());
342      return false;
343    }
344    private bool RemoveParameterName(string name) {
345      if (!list.Any(x => x.Parameters.ContainsKey(name))) {
346        parameterNames.Remove(name);
347        return true;
348      }
349      return false;
350    }
351    private bool RemoveResultName(string name) {
352      if (!list.Any(x => x.Results.ContainsKey(name))) {
353        resultNames.Remove(name);
354        return true;
355      }
356      return false;
357    }
358
359    public IItem GetValue(int rowIndex, int columnIndex) {
360      IRun run = this.list[rowIndex];
361      return GetValue(run, columnIndex);
362    }
363
364    public IItem GetValue(IRun run, int columnIndex) {
365      string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
366      return GetValue(run, name);
367    }
368
369    public IItem GetValue(IRun run, string columnName) {
370      IItem value = null;
371      if (run.Parameters.ContainsKey(columnName))
372        value = run.Parameters[columnName];
373      else if (run.Results.ContainsKey(columnName))
374        value = run.Results[columnName];
375      return value;
376    }
377
378    #region IStringConvertibleMatrix Members
379    [Storable]
380    private List<string> parameterNames;
381    public IEnumerable<string> ParameterNames {
382      get { return this.parameterNames; }
383    }
384    [Storable]
385    private List<string> resultNames;
386    public IEnumerable<string> ResultNames {
387      get { return this.resultNames; }
388    }
389    int IStringConvertibleMatrix.Rows {
390      get { return this.Count; }
391      set { throw new NotSupportedException(); }
392    }
393    int IStringConvertibleMatrix.Columns {
394      get { return parameterNames.Count + resultNames.Count; }
395      set { throw new NotSupportedException(); }
396    }
397    private List<string> columnNameCache;
398    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
399      get {
400        if (columnNameCache == null) {
401          columnNameCache = new List<string>(parameterNames);
402          columnNameCache.AddRange(resultNames);
403          columnNameCache.Sort();
404        }
405        return columnNameCache;
406      }
407      set { throw new NotSupportedException(); }
408    }
409    private List<string> rowNamesCache;
410    IEnumerable<string> IStringConvertibleMatrix.RowNames {
411      get {
412        if (rowNamesCache == null)
413          rowNamesCache = list.Select(x => x.Name).ToList();
414        return rowNamesCache;
415      }
416      set { throw new NotSupportedException(); }
417    }
418    bool IStringConvertibleMatrix.SortableView {
419      get { return true; }
420      set { throw new NotSupportedException(); }
421    }
422    bool IStringConvertibleMatrix.ReadOnly {
423      get { return true; }
424    }
425
426    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
427      IItem value = GetValue(rowIndex, columnIndex);
428      if (value == null)
429        return string.Empty;
430      return value.ToString();
431    }
432
433    public event EventHandler<EventArgs<int, int>> ItemChanged;
434    protected virtual void OnItemChanged(int rowIndex, int columnIndex) {
435      EventHandler<EventArgs<int, int>> handler = ItemChanged;
436      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
437      OnToStringChanged();
438    }
439    public event EventHandler Reset;
440    protected virtual void OnReset() {
441      EventHandler handler = Reset;
442      if (handler != null) handler(this, EventArgs.Empty);
443      OnToStringChanged();
444    }
445    public event EventHandler ColumnsChanged;
446    protected virtual void OnColumnsChanged() {
447      var handler = ColumnsChanged;
448      if (handler != null) handler(this, EventArgs.Empty);
449    }
450    public event EventHandler RowsChanged;
451    protected virtual void OnRowsChanged() {
452      var handler = RowsChanged;
453      if (handler != null) handler(this, EventArgs.Empty);
454    }
455    public event EventHandler ColumnNamesChanged;
456    protected virtual void OnColumnNamesChanged() {
457      EventHandler handler = ColumnNamesChanged;
458      if (handler != null) handler(this, EventArgs.Empty);
459    }
460    public event EventHandler RowNamesChanged;
461    protected virtual void OnRowNamesChanged() {
462      EventHandler handler = RowNamesChanged;
463      if (handler != null) handler(this, EventArgs.Empty);
464    }
465    public event EventHandler SortableViewChanged;
466    protected virtual void OnSortableViewChanged() {
467      EventHandler handler = SortableViewChanged;
468      if (handler != null) handler(this, EventArgs.Empty);
469    }
470
471    public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); }
472    public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); }
473    #endregion
474
475    #region Filtering
476    private void UpdateFiltering(bool reset) {
477      UpdateOfRunsInProgress = true;
478      if (reset)
479        list.ForEach(r => r.Visible = true);
480      foreach (IRunCollectionConstraint constraint in this.constraints)
481        constraint.Check();
482      UpdateOfRunsInProgress = false;
483    }
484
485    private void RegisterConstraintsEvents() {
486      constraints.ItemsAdded += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsAdded);
487      constraints.ItemsRemoved += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsRemoved);
488      constraints.CollectionReset += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_CollectionReset);
489    }
490
491    protected virtual void RegisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
492      foreach (IRunCollectionConstraint constraint in constraints) {
493        constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged);
494        constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged);
495        constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged);
496        constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged);
497      }
498    }
499    protected virtual void DeregisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
500      foreach (IRunCollectionConstraint constraint in constraints) {
501        constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged);
502        constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged);
503        constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged);
504        constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged);
505      }
506    }
507
508    protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
509      DeregisterConstraintEvents(e.OldItems);
510      RegisterConstraintEvents(e.Items);
511      this.UpdateFiltering(true);
512    }
513    protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
514      RegisterConstraintEvents(e.Items);
515      foreach (IRunCollectionConstraint constraint in e.Items)
516        constraint.ConstrainedValue = this;
517      this.UpdateFiltering(false);
518    }
519    protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
520      DeregisterConstraintEvents(e.Items);
521      this.UpdateFiltering(true);
522    }
523    protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) {
524      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
525      this.UpdateFiltering(!constraint.Active);
526    }
527    protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) {
528      //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method
529    }
530    protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) {
531      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
532      if (constraint.Active)
533        this.UpdateFiltering(true);
534    }
535    protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) {
536      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
537      if (constraint.Active)
538        this.UpdateFiltering(true);
539    }
540    #endregion
541
542    #region Modification
543    public void Modify() {
544      UpdateOfRunsInProgress = true;
545      var runs = this.ToList();
546      var selectedRuns = runs.Where(r => r.Visible).ToList();
547      int nSelected = selectedRuns.Count;
548      if (nSelected > 0) {
549        foreach (var modifier in Modifiers.CheckedItems)
550          modifier.Value.Modify(selectedRuns);
551        if (nSelected != selectedRuns.Count || HaveDifferentOrder(selectedRuns, runs.Where(r => r.Visible))) {
552          Clear();
553          AddRange(ReplaceVisibleRuns(runs, selectedRuns));
554        } else if (runs.Count > 0) {
555          OnCollectionReset(this, runs);
556        }
557      }
558      UpdateOfRunsInProgress = false;
559    }
560
561    private static IEnumerable<IRun> ReplaceVisibleRuns(IEnumerable<IRun> runs, IEnumerable<IRun> visibleRuns) {
562      var newRuns = new List<IRun>();
563      var runIt = runs.GetEnumerator();
564      var visibleRunIt = visibleRuns.GetEnumerator();
565      while (runIt.MoveNext()) {
566        if (runIt.Current != null && !runIt.Current.Visible)
567          newRuns.Add(runIt.Current);
568        else if (visibleRunIt.MoveNext())
569          newRuns.Add(visibleRunIt.Current);
570      }
571      while (visibleRunIt.MoveNext())
572        newRuns.Add(visibleRunIt.Current);
573      return newRuns;
574    }
575
576    private static bool HaveDifferentOrder(IEnumerable<IRun> l1, IEnumerable<IRun> l2) {
577      return l1.Zip(l2, (r1, r2) => r1 != r2).Any();
578    }
579    #endregion
580  }
581}
Note: See TracBrowser for help on using the repository browser.