source: branches/TerminationCriteria/HeuristicLab.Optimization/3.3/RunCollection.cs @ 12809

Last change on this file since 12809 was 12809, checked in by pfleck, 5 years ago

#2027 Merged trunk changes.

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