Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/RunCollection.cs @ 17577

Last change on this file since 17577 was 17226, checked in by mkommend, 5 years ago

#2521: Merged trunk changes into problem refactoring branch.

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