Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization/3.3/RunCollection.cs @ 11344

Last change on this file since 11344 was 11344, checked in by abeham, 10 years ago

#2120:

  • Parameters and Results are now ObservableDictionaries
  • PropertyChanged event handler replaces the Changed event handler
  • RunCollection listens to changed events to each run's parameters and results (8 additional event handlers per run)
File size: 21.3 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 += RunOnParameterChanged;
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 += RunOnResultChanged;
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 -= RunOnParameterChanged;
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 -= RunOnResultChanged;
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 RunOnResultChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
283      bool columnsChanged = false;
284      foreach (var result in e.Items)
285        columnsChanged |= AddResult(result.Key, result.Value);
286      foreach (var result in e.OldItems)
287        columnsChanged |= RemoveResultName(result.Key);
288      if (columnsChanged) columnNameCache = null;
289      OnReset();
290      if (columnsChanged) {
291        OnColumnsChanged();
292        OnColumnNamesChanged();
293      }
294    }
295
296    private bool AddParameter(string name, IItem value) {
297      if (value == null)
298        return false;
299      if (!parameterNames.Contains(name)) {
300        parameterNames.Add(name);
301        dataTypes[name] = new HashSet<Type>();
302        dataTypes[name].Add(value.GetType());
303        return true;
304      }
305      dataTypes[name].Add(value.GetType());
306      return false;
307    }
308    private bool AddResult(string name, IItem value) {
309      if (value == null)
310        return false;
311      if (!resultNames.Contains(name)) {
312        resultNames.Add(name);
313        dataTypes[name] = new HashSet<Type>();
314        dataTypes[name].Add(value.GetType());
315        return true;
316      }
317      dataTypes[name].Add(value.GetType());
318      return false;
319    }
320    private bool RemoveParameterName(string name) {
321      if (!list.Any(x => x.Parameters.ContainsKey(name))) {
322        parameterNames.Remove(name);
323        return true;
324      }
325      return false;
326    }
327    private bool RemoveResultName(string name) {
328      if (!list.Any(x => x.Results.ContainsKey(name))) {
329        resultNames.Remove(name);
330        return true;
331      }
332      return false;
333    }
334
335    public IItem GetValue(int rowIndex, int columnIndex) {
336      IRun run = this.list[rowIndex];
337      return GetValue(run, columnIndex);
338    }
339
340    public IItem GetValue(IRun run, int columnIndex) {
341      string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
342      return GetValue(run, name);
343    }
344
345    public IItem GetValue(IRun run, string columnName) {
346      IItem value = null;
347      if (run.Parameters.ContainsKey(columnName))
348        value = run.Parameters[columnName];
349      else if (run.Results.ContainsKey(columnName))
350        value = run.Results[columnName];
351      return value;
352    }
353
354    #region IStringConvertibleMatrix Members
355    [Storable]
356    private List<string> parameterNames;
357    public IEnumerable<string> ParameterNames {
358      get { return this.parameterNames; }
359    }
360    [Storable]
361    private List<string> resultNames;
362    public IEnumerable<string> ResultNames {
363      get { return this.resultNames; }
364    }
365    int IStringConvertibleMatrix.Rows {
366      get { return this.Count; }
367      set { throw new NotSupportedException(); }
368    }
369    int IStringConvertibleMatrix.Columns {
370      get { return parameterNames.Count + resultNames.Count; }
371      set { throw new NotSupportedException(); }
372    }
373    private List<string> columnNameCache;
374    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
375      get {
376        if (columnNameCache == null) {
377          columnNameCache = new List<string>(parameterNames);
378          columnNameCache.AddRange(resultNames);
379          columnNameCache.Sort();
380        }
381        return columnNameCache;
382      }
383      set { throw new NotSupportedException(); }
384    }
385    private List<string> rowNamesCache;
386    IEnumerable<string> IStringConvertibleMatrix.RowNames {
387      get {
388        if (rowNamesCache == null)
389          rowNamesCache = list.Select(x => x.Name).ToList();
390        return rowNamesCache;
391      }
392      set { throw new NotSupportedException(); }
393    }
394    bool IStringConvertibleMatrix.SortableView {
395      get { return true; }
396      set { throw new NotSupportedException(); }
397    }
398    bool IStringConvertibleMatrix.ReadOnly {
399      get { return true; }
400    }
401
402    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
403      IItem value = GetValue(rowIndex, columnIndex);
404      if (value == null)
405        return string.Empty;
406      return value.ToString();
407    }
408
409    public event EventHandler<EventArgs<int, int>> ItemChanged;
410    protected virtual void OnItemChanged(int rowIndex, int columnIndex) {
411      EventHandler<EventArgs<int, int>> handler = ItemChanged;
412      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
413      OnToStringChanged();
414    }
415    public event EventHandler Reset;
416    protected virtual void OnReset() {
417      EventHandler handler = Reset;
418      if (handler != null) handler(this, EventArgs.Empty);
419      OnToStringChanged();
420    }
421    public event EventHandler ColumnsChanged;
422    protected virtual void OnColumnsChanged() {
423      var handler = ColumnsChanged;
424      if (handler != null) handler(this, EventArgs.Empty);
425    }
426    public event EventHandler RowsChanged;
427    protected virtual void OnRowsChanged() {
428      var handler = RowsChanged;
429      if (handler != null) handler(this, EventArgs.Empty);
430    }
431    public event EventHandler ColumnNamesChanged;
432    protected virtual void OnColumnNamesChanged() {
433      EventHandler handler = ColumnNamesChanged;
434      if (handler != null) handler(this, EventArgs.Empty);
435    }
436    public event EventHandler RowNamesChanged;
437    protected virtual void OnRowNamesChanged() {
438      EventHandler handler = RowNamesChanged;
439      if (handler != null) handler(this, EventArgs.Empty);
440    }
441    public event EventHandler SortableViewChanged;
442    protected virtual void OnSortableViewChanged() {
443      EventHandler handler = SortableViewChanged;
444      if (handler != null) handler(this, EventArgs.Empty);
445    }
446
447    public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); }
448    public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); }
449    #endregion
450
451    #region Filtering
452    private void UpdateFiltering(bool reset) {
453      UpdateOfRunsInProgress = true;
454      if (reset)
455        list.ForEach(r => r.Visible = true);
456      foreach (IRunCollectionConstraint constraint in this.constraints)
457        constraint.Check();
458      UpdateOfRunsInProgress = false;
459    }
460
461    private void RegisterConstraintsEvents() {
462      constraints.ItemsAdded += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsAdded);
463      constraints.ItemsRemoved += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsRemoved);
464      constraints.CollectionReset += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_CollectionReset);
465    }
466
467    protected virtual void RegisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
468      foreach (IRunCollectionConstraint constraint in constraints) {
469        constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged);
470        constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged);
471        constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged);
472        constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged);
473      }
474    }
475    protected virtual void DeregisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
476      foreach (IRunCollectionConstraint constraint in constraints) {
477        constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged);
478        constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged);
479        constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged);
480        constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged);
481      }
482    }
483
484    protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
485      DeregisterConstraintEvents(e.OldItems);
486      RegisterConstraintEvents(e.Items);
487      this.UpdateFiltering(true);
488    }
489    protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
490      RegisterConstraintEvents(e.Items);
491      foreach (IRunCollectionConstraint constraint in e.Items)
492        constraint.ConstrainedValue = this;
493      this.UpdateFiltering(false);
494    }
495    protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
496      DeregisterConstraintEvents(e.Items);
497      this.UpdateFiltering(true);
498    }
499    protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) {
500      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
501      this.UpdateFiltering(!constraint.Active);
502    }
503    protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) {
504      //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method
505    }
506    protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) {
507      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
508      if (constraint.Active)
509        this.UpdateFiltering(true);
510    }
511    protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) {
512      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
513      if (constraint.Active)
514        this.UpdateFiltering(true);
515    }
516    #endregion
517
518    #region Modification
519    public void Modify() {
520      UpdateOfRunsInProgress = true;
521      var runs = this.ToList();
522      var selectedRuns = runs.Where(r => r.Visible).ToList();
523      int nSelected = selectedRuns.Count;
524      if (nSelected > 0) {
525        foreach (var modifier in Modifiers.CheckedItems)
526          modifier.Value.Modify(selectedRuns);
527        if (nSelected != selectedRuns.Count || HaveDifferentOrder(selectedRuns, runs.Where(r => r.Visible))) {
528          Clear();
529          AddRange(ReplaceVisibleRuns(runs, selectedRuns));
530        } else if (runs.Count > 0) {
531          OnCollectionReset(this, runs);
532        }
533      }
534      UpdateOfRunsInProgress = false;
535    }
536
537    private static IEnumerable<IRun> ReplaceVisibleRuns(IEnumerable<IRun> runs, IEnumerable<IRun> visibleRuns) {
538      var newRuns = new List<IRun>();
539      var runIt = runs.GetEnumerator();
540      var visibleRunIt = visibleRuns.GetEnumerator();
541      while (runIt.MoveNext()) {
542        if (runIt.Current != null && !runIt.Current.Visible)
543          newRuns.Add(runIt.Current);
544        else if (visibleRunIt.MoveNext())
545          newRuns.Add(visibleRunIt.Current);
546      }
547      while (visibleRunIt.MoveNext())
548        newRuns.Add(visibleRunIt.Current);
549      return newRuns;
550    }
551
552    private static bool HaveDifferentOrder(IEnumerable<IRun> l1, IEnumerable<IRun> l2) {
553      return l1.Zip(l2, (r1, r2) => r1 != r2).Any();
554    }
555    #endregion
556  }
557}
Note: See TracBrowser for help on using the repository browser.