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

Last change on this file since 8738 was 8738, checked in by mkommend, 8 years ago

#1673: Added new property AlgorithmName to the RunCollection and synced the property with the name of the surrounding IOptimizer. The AlgorithmName is used by the RunCollectionViews as prefix for its caption if it was set.

File size: 17.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Collections;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.Optimization {
32  [Item("Run Collection", "Represents a collection of runs.")]
33  [Creatable("Testing & Analysis")]
34  [StorableClass]
35  public class RunCollection : ItemCollection<IRun>, IStringConvertibleMatrix, IStorableContent {
36    public string Filename { get; set; }
37
38    [StorableConstructor]
39    protected RunCollection(bool deserializing)
40      : base(deserializing) {
41      updateOfRunsInProgress = false;
42    }
43    protected RunCollection(RunCollection original, Cloner cloner)
44      : base(original, cloner) {
45      updateOfRunsInProgress = false;
46      algorithmName = original.algorithmName;
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      UpdateFiltering(true);
62    }
63    public RunCollection() : base() { Initialize(); }
64    public RunCollection(int capacity) : base(capacity) { Initialize(); }
65    public RunCollection(IEnumerable<IRun> collection) : base(collection) { Initialize(); this.OnItemsAdded(collection); }
66    private void Initialize() {
67      updateOfRunsInProgress = false;
68      parameterNames = new List<string>();
69      resultNames = new List<string>();
70      dataTypes = new Dictionary<string, HashSet<Type>>();
71      constraints = new RunCollectionConstraintCollection();
72      modifiers = new CheckedItemList<IRunCollectionModifier>();
73      RegisterConstraintsEvents();
74    }
75
76    [Storable]
77    private Dictionary<string, HashSet<Type>> dataTypes;
78    public IEnumerable<Type> GetDataType(string columnName) {
79      if (!dataTypes.ContainsKey(columnName))
80        return new Type[0];
81      return dataTypes[columnName];
82    }
83
84    [Storable]
85    private RunCollectionConstraintCollection constraints;
86    public RunCollectionConstraintCollection Constraints {
87      get { return constraints; }
88    }
89
90    [Storable]
91    private CheckedItemList<IRunCollectionModifier> modifiers;
92    public CheckedItemList<IRunCollectionModifier> Modifiers {
93      get { return modifiers; }
94    }
95
96
97    private bool updateOfRunsInProgress;
98    public bool UpdateOfRunsInProgress {
99      get { return updateOfRunsInProgress; }
100      set {
101        if (updateOfRunsInProgress != value) {
102          updateOfRunsInProgress = value;
103          OnUpdateOfRunsInProgressChanged();
104        }
105      }
106    }
107
108    private string algorithmName = string.Empty;
109    [Storable]
110    public string AlgorithmName {
111      get { return algorithmName; }
112      set {
113        if (value != algorithmName && !string.IsNullOrEmpty(value)) {
114          algorithmName = value;
115          OnAlgorithmNameChanged();
116        }
117      }
118    }
119
120    [StorableHook(HookType.AfterDeserialization)]
121    private void AfterDeserialization() {
122      if (constraints == null) constraints = new RunCollectionConstraintCollection();
123      if (modifiers == null) modifiers = new CheckedItemList<IRunCollectionModifier>();
124      RegisterConstraintsEvents();
125      RegisterConstraintEvents(constraints);
126      UpdateFiltering(true);
127    }
128
129    public override IDeepCloneable Clone(Cloner cloner) {
130      return new RunCollection(this, cloner);
131    }
132
133    public event EventHandler UpdateOfRunsInProgressChanged;
134    protected virtual void OnUpdateOfRunsInProgressChanged() {
135      var handler = UpdateOfRunsInProgressChanged;
136      if (handler != null) handler(this, EventArgs.Empty);
137    }
138
139    public event EventHandler AlgorithmNameChanged;
140    protected virtual void OnAlgorithmNameChanged() {
141      var handler = AlgorithmNameChanged;
142      if (handler != null) handler(this, EventArgs.Empty);
143    }
144
145    protected override void OnCollectionReset(IEnumerable<IRun> items, IEnumerable<IRun> oldItems) {
146      parameterNames.Clear();
147      resultNames.Clear();
148      dataTypes.Clear();
149      foreach (IRun run in items) {
150        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
151          AddParameter(parameter.Key, parameter.Value);
152        foreach (KeyValuePair<string, IItem> result in run.Results)
153          AddResult(result.Key, result.Value);
154      }
155      columnNameCache = null;
156      OnColumnsChanged();
157      OnColumnNamesChanged();
158      rowNamesCache = null;
159      base.OnCollectionReset(items, oldItems);
160      OnRowsChanged();
161      OnRowNamesChanged();
162      OnReset();
163      UpdateFiltering(false);
164    }
165    protected override void OnItemsAdded(IEnumerable<IRun> items) {
166      bool columnsChanged = false;
167      foreach (IRun run in items) {
168        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
169          columnsChanged |= AddParameter(parameter.Key, parameter.Value);
170        foreach (KeyValuePair<string, IItem> result in run.Results)
171          columnsChanged |= AddResult(result.Key, result.Value);
172      }
173      if (columnsChanged) columnNameCache = null;
174      rowNamesCache = null;
175      base.OnItemsAdded(items);
176      OnReset();
177      OnRowsChanged();
178      OnRowNamesChanged();
179      if (columnsChanged) {
180        OnColumnsChanged();
181        OnColumnNamesChanged();
182      }
183      UpdateFiltering(false);
184    }
185    protected override void OnItemsRemoved(IEnumerable<IRun> items) {
186      bool columnsChanged = false;
187      foreach (IRun run in items) {
188        foreach (string parameterName in run.Parameters.Keys)
189          columnsChanged |= RemoveParameterName(parameterName);
190        foreach (string resultName in run.Results.Keys)
191          columnsChanged |= RemoveResultName(resultName);
192      }
193      if (columnsChanged) columnNameCache = null;
194      rowNamesCache = null;
195      base.OnItemsRemoved(items);
196      OnReset();
197      OnRowsChanged();
198      OnRowNamesChanged();
199      if (columnsChanged) {
200        OnColumnsChanged();
201        OnColumnNamesChanged();
202      }
203    }
204
205    private bool AddParameter(string name, IItem value) {
206      if (value == null)
207        return false;
208      if (!parameterNames.Contains(name)) {
209        parameterNames.Add(name);
210        dataTypes[name] = new HashSet<Type>();
211        dataTypes[name].Add(value.GetType());
212        return true;
213      }
214      dataTypes[name].Add(value.GetType());
215      return false;
216    }
217    private bool AddResult(string name, IItem value) {
218      if (value == null)
219        return false;
220      if (!resultNames.Contains(name)) {
221        resultNames.Add(name);
222        dataTypes[name] = new HashSet<Type>();
223        dataTypes[name].Add(value.GetType());
224        return true;
225      }
226      dataTypes[name].Add(value.GetType());
227      return false;
228    }
229    private bool RemoveParameterName(string name) {
230      if (!list.Any(x => x.Parameters.ContainsKey(name))) {
231        parameterNames.Remove(name);
232        return true;
233      }
234      return false;
235    }
236    private bool RemoveResultName(string name) {
237      if (!list.Any(x => x.Results.ContainsKey(name))) {
238        resultNames.Remove(name);
239        return true;
240      }
241      return false;
242    }
243
244    public IItem GetValue(int rowIndex, int columnIndex) {
245      IRun run = this.list[rowIndex];
246      return GetValue(run, columnIndex);
247    }
248
249    public IItem GetValue(IRun run, int columnIndex) {
250      string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
251      return GetValue(run, name);
252    }
253
254    public IItem GetValue(IRun run, string columnName) {
255      IItem value = null;
256      if (run.Parameters.ContainsKey(columnName))
257        value = run.Parameters[columnName];
258      else if (run.Results.ContainsKey(columnName))
259        value = run.Results[columnName];
260      return value;
261    }
262
263    #region IStringConvertibleMatrix Members
264    [Storable]
265    private List<string> parameterNames;
266    public IEnumerable<string> ParameterNames {
267      get { return this.parameterNames; }
268    }
269    [Storable]
270    private List<string> resultNames;
271    public IEnumerable<string> ResultNames {
272      get { return this.resultNames; }
273    }
274    int IStringConvertibleMatrix.Rows {
275      get { return this.Count; }
276      set { throw new NotSupportedException(); }
277    }
278    int IStringConvertibleMatrix.Columns {
279      get { return parameterNames.Count + resultNames.Count; }
280      set { throw new NotSupportedException(); }
281    }
282    private List<string> columnNameCache;
283    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
284      get {
285        if (columnNameCache == null) {
286          columnNameCache = new List<string>(parameterNames);
287          columnNameCache.AddRange(resultNames);
288          columnNameCache.Sort();
289        }
290        return columnNameCache;
291      }
292      set { throw new NotSupportedException(); }
293    }
294    private List<string> rowNamesCache;
295    IEnumerable<string> IStringConvertibleMatrix.RowNames {
296      get {
297        if (rowNamesCache == null)
298          rowNamesCache = list.Select(x => x.Name).ToList();
299        return rowNamesCache;
300      }
301      set { throw new NotSupportedException(); }
302    }
303    bool IStringConvertibleMatrix.SortableView {
304      get { return true; }
305      set { throw new NotSupportedException(); }
306    }
307    bool IStringConvertibleMatrix.ReadOnly {
308      get { return true; }
309    }
310
311    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
312      IItem value = GetValue(rowIndex, columnIndex);
313      if (value == null)
314        return string.Empty;
315      return value.ToString();
316    }
317
318    public event EventHandler<EventArgs<int, int>> ItemChanged;
319    protected virtual void OnItemChanged(int rowIndex, int columnIndex) {
320      EventHandler<EventArgs<int, int>> handler = ItemChanged;
321      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
322      OnToStringChanged();
323    }
324    public event EventHandler Reset;
325    protected virtual void OnReset() {
326      EventHandler handler = Reset;
327      if (handler != null) handler(this, EventArgs.Empty);
328      OnToStringChanged();
329    }
330    public event EventHandler ColumnsChanged;
331    protected virtual void OnColumnsChanged() {
332      var handler = ColumnsChanged;
333      if (handler != null) handler(this, EventArgs.Empty);
334    }
335    public event EventHandler RowsChanged;
336    protected virtual void OnRowsChanged() {
337      var handler = RowsChanged;
338      if (handler != null) handler(this, EventArgs.Empty);
339    }
340    public event EventHandler ColumnNamesChanged;
341    protected virtual void OnColumnNamesChanged() {
342      EventHandler handler = ColumnNamesChanged;
343      if (handler != null) handler(this, EventArgs.Empty);
344    }
345    public event EventHandler RowNamesChanged;
346    protected virtual void OnRowNamesChanged() {
347      EventHandler handler = RowNamesChanged;
348      if (handler != null) handler(this, EventArgs.Empty);
349    }
350    public event EventHandler SortableViewChanged;
351    protected virtual void OnSortableViewChanged() {
352      EventHandler handler = SortableViewChanged;
353      if (handler != null) handler(this, EventArgs.Empty);
354    }
355
356    public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); }
357    public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); }
358    #endregion
359
360    #region Filtering
361    private void UpdateFiltering(bool reset) {
362      UpdateOfRunsInProgress = true;
363      if (reset)
364        list.ForEach(r => r.Visible = true);
365      foreach (IRunCollectionConstraint constraint in this.constraints)
366        constraint.Check();
367      UpdateOfRunsInProgress = false;
368    }
369
370    private void RegisterConstraintsEvents() {
371      constraints.ItemsAdded += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsAdded);
372      constraints.ItemsRemoved += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsRemoved);
373      constraints.CollectionReset += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_CollectionReset);
374    }
375
376    protected virtual void RegisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
377      foreach (IRunCollectionConstraint constraint in constraints) {
378        constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged);
379        constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged);
380        constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged);
381        constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged);
382      }
383    }
384    protected virtual void DeregisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
385      foreach (IRunCollectionConstraint constraint in constraints) {
386        constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged);
387        constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged);
388        constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged);
389        constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged);
390      }
391    }
392
393    protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
394      DeregisterConstraintEvents(e.OldItems);
395      RegisterConstraintEvents(e.Items);
396      this.UpdateFiltering(true);
397    }
398    protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
399      RegisterConstraintEvents(e.Items);
400      foreach (IRunCollectionConstraint constraint in e.Items)
401        constraint.ConstrainedValue = this;
402      this.UpdateFiltering(false);
403    }
404    protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
405      DeregisterConstraintEvents(e.Items);
406      this.UpdateFiltering(true);
407    }
408    protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) {
409      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
410      this.UpdateFiltering(!constraint.Active);
411    }
412    protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) {
413      //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method
414    }
415    protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) {
416      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
417      if (constraint.Active)
418        this.UpdateFiltering(true);
419    }
420    protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) {
421      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
422      if (constraint.Active)
423        this.UpdateFiltering(true);
424    }
425    #endregion
426
427    #region Modification
428    public void Modify() {
429      UpdateOfRunsInProgress = true;
430      var runs = this.ToList();
431      var selectedRuns = runs.Where(r => r.Visible).ToList();
432      int nSelected = selectedRuns.Count;
433      if (nSelected > 0) {
434        foreach (var modifier in Modifiers.CheckedItems)
435          modifier.Value.Modify(selectedRuns);
436        if (nSelected != selectedRuns.Count || HaveDifferentOrder(selectedRuns, runs.Where(r => r.Visible))) {
437          Clear();
438          AddRange(ReplaceVisibleRuns(runs, selectedRuns));
439        } else if (runs.Count > 0) {
440          OnCollectionReset(this, runs);
441        }
442      }
443      UpdateOfRunsInProgress = false;
444    }
445
446    private static IEnumerable<IRun> ReplaceVisibleRuns(IEnumerable<IRun> runs, IEnumerable<IRun> visibleRuns) {
447      var newRuns = new List<IRun>();
448      var runIt = runs.GetEnumerator();
449      var visibleRunIt = visibleRuns.GetEnumerator();
450      while (runIt.MoveNext()) {
451        if (runIt.Current != null && !runIt.Current.Visible)
452          newRuns.Add(runIt.Current);
453        else if (visibleRunIt.MoveNext())
454          newRuns.Add(visibleRunIt.Current);
455      }
456      while (visibleRunIt.MoveNext())
457        newRuns.Add(visibleRunIt.Current);
458      return newRuns;
459    }
460
461    private static bool HaveDifferentOrder(IEnumerable<IRun> l1, IEnumerable<IRun> l2) {
462      return l1.Zip(l2, (r1, r2) => r1 != r2).Any();
463    }
464    #endregion
465  }
466}
Note: See TracBrowser for help on using the repository browser.