Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.MetaOptimization/HeuristicLab.Problems.MetaOptimization/3.3/Encoding/ParameterConfigurations/ParameterConfiguration.cs @ 5359

Last change on this file since 5359 was 5359, checked in by cneumuel, 13 years ago

#1215

  • renamed RunsAnalyzer to SolutionCacheAnalyzer
  • only most recent results will stay in cache to avoid memory problems
  • some minor tweaks and bugfixes
File size: 19.0 KB
Line 
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Linq;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using HeuristicLab.Parameters;
9using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
10using HeuristicLab.PluginInfrastructure;
11using System.Text;
12using System.Reflection;
13using HeuristicLab.Optimization;
14using HeuristicLab.Collections;
15using System.Drawing;
16
17namespace HeuristicLab.Problems.MetaOptimization {
18  [StorableClass]
19  public class ParameterConfiguration : Item, IParameterConfiguration, IStorableContent {
20    public bool IsOptimizable {
21      get { return true; }
22    }
23
24    [Storable]
25    public string Filename { get; set; }
26
27    [Storable]
28    protected bool optimize;
29    public bool Optimize {
30      get { return optimize; }
31      set {
32        if (optimize != value) {
33          optimize = value;
34          if (optimize) {
35            PopulateValueConfigurations();
36          } else {
37            this.ValueConfigurations.Clear();
38          }
39          OnOptimizeChanged();
40          OnToStringChanged();
41        }
42      }
43    }
44
45    [Storable]
46    private Image itemImage;
47    public virtual Image ItemImage {
48      get { return itemImage ?? base.ItemImage; }
49    }
50
51    [Storable]
52    protected string parameterName;
53    public string ParameterName {
54      get { return parameterName; }
55      set {
56        if (parameterName != value) {
57          parameterName = value;
58          OnToStringChanged();
59        }
60      }
61    }
62
63    [Storable]
64    protected Type parameterDataType;
65    public Type ParameterDataType {
66      get { return this.parameterDataType; }
67    }
68
69    [Storable]
70    protected Type[] validTypes;
71    public Type[] ValidTypes {
72      get { return validTypes; }
73      protected set {
74        if (this.validTypes != value) {
75          this.validTypes = value;
76        }
77      }
78    }
79
80    [Storable]
81    protected Type valueDataType;
82    public Type ValueDataType {
83      get { return valueDataType; }
84      protected set { this.valueDataType = value; }
85    }
86
87    [Storable]
88    protected ICheckedValueConfigurationList valueConfigurations;
89    public ICheckedValueConfigurationList ValueConfigurations {
90      get { return this.valueConfigurations; }
91      protected set {
92        if (this.valueConfigurations != value) {
93          if (this.valueConfigurations != null) DeregisterValueConfigurationEvents();
94          this.valueConfigurations = value;
95          if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
96        }
97      }
98    }
99
100    [Storable]
101    private int actualValueConfigurationIndex = 0;
102    public int ActualValueConfigurationIndex {
103      get { return actualValueConfigurationIndex; }
104      set { actualValueConfigurationIndex = value; }
105    }
106
107    [Storable]
108    protected ConstrainedValue actualValue;
109    public ConstrainedValue ActualValue {
110      get { return actualValue; }
111      set {
112        if (actualValue != value) {
113          DeregisterActualValueEvents();
114          actualValue = value;
115          RegisterActualValueEvents();
116        }
117      }
118    }
119
120    [Storable]
121    protected bool isNullable;
122    public bool IsNullable {
123      get { return isNullable; }
124      protected set {
125        if (this.isNullable != value) {
126          this.isNullable = value;
127        }
128      }
129    }
130
131    [Storable]
132    protected IItemSet<IItem> validValues;
133
134    #region Constructors and Cloning
135    public ParameterConfiguration(string parameterName, IValueParameter valueParameter) {
136      this.ParameterName = parameterName;
137      this.parameterDataType = valueParameter.GetType();
138      this.valueDataType = valueParameter.DataType;
139      this.validValues = GetValidValues(valueParameter);
140      this.validTypes = GetValidTypes(valueParameter).ToArray();
141      this.IsNullable = valueParameter.ItemName.StartsWith("Optional");
142      this.itemImage = valueParameter.ItemImage;
143      if (IsNullable) {
144        validTypes = new List<Type>(validTypes) { typeof(NullValue) }.ToArray();
145      }
146      this.ValueConfigurations = new CheckedValueConfigurationList(this.validValues ?? CreateValidValues());
147      this.ActualValue = new ConstrainedValue(
148        valueParameter.Value != null ? (IItem)valueParameter.Value.Clone() : null,
149        valueParameter.DataType,
150        this.validValues != null ? new ItemSet<IItem>(this.validValues) : CreateValidValues(),
151        this.IsNullable);
152      if (Optimize) {
153        PopulateValueConfigurations();
154      }
155    }
156
157    public ParameterConfiguration() { }
158    [StorableConstructor]
159    protected ParameterConfiguration(bool deserializing) { }
160    protected ParameterConfiguration(ParameterConfiguration original, Cloner cloner)
161      : base(original, cloner) {
162      this.parameterName = original.ParameterName;
163      this.parameterDataType = original.parameterDataType;
164      this.valueDataType = original.ValueDataType;
165      this.validValues = cloner.Clone(original.validValues);
166      this.validTypes = original.validTypes.ToArray();
167      this.valueConfigurations = cloner.Clone(original.ValueConfigurations);
168      this.ActualValue = cloner.Clone(original.ActualValue);
169      this.optimize = original.optimize;
170      this.actualValueConfigurationIndex = original.actualValueConfigurationIndex;
171      this.isNullable = original.isNullable;
172      this.itemImage = original.itemImage;
173      if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
174    }
175    public override IDeepCloneable Clone(Cloner cloner) {
176      return new ParameterConfiguration(this, cloner);
177    }
178    [StorableHook(HookType.AfterDeserialization)]
179    private void AfterDeserialization() {
180      if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
181    }
182    #endregion
183
184    private void RegisterValueConfigurationEvents() {
185      this.ValueConfigurations.CheckedItemsChanged += new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_CheckedItemsChanged);
186      this.ValueConfigurations.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_ItemsAdded);
187      this.ValueConfigurations.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_ItemsRemoved);
188    }
189
190    private void DeregisterValueConfigurationEvents() {
191      this.ValueConfigurations.CheckedItemsChanged -= new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_CheckedItemsChanged);
192      this.ValueConfigurations.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_ItemsAdded);
193      this.ValueConfigurations.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IValueConfiguration>>(ValueConfigurations_ItemsRemoved);
194    }
195
196    private void RegisterActualValueEvents() {
197      if (this.ActualValue != null) this.ActualValue.ToStringChanged += new EventHandler(ActualValue_ToStringChanged);
198    }
199    private void DeregisterActualValueEvents() {
200      if (this.ActualValue != null) this.ActualValue.ToStringChanged -= new EventHandler(ActualValue_ToStringChanged);
201    }
202
203    private void PopulateValueConfigurations() {
204      foreach (Type t in this.validTypes) {
205        if (t == typeof(NullValue)) {
206          this.ValueConfigurations.Add(new NullValueConfiguration());
207        } else {
208          IItem val;
209          if (ActualValue.Value != null && ActualValue.ValueDataType == t) {
210            val = (IItem)ActualValue.Value.Clone(); // use existing value for that type (if available)
211          } else {
212            val = CreateItem(t);
213          }
214          this.ValueConfigurations.Add(new ValueConfiguration(val, val.GetType()), true);
215        }
216      }
217    }
218
219    private static IEnumerable<Type> GetValidTypes(IValueParameter parameter) {
220      // in case of IOperator return empty list, otherwise hundreds of types would be returned. this mostly occurs for Successor which will never be optimized
221      if (parameter.DataType == typeof(IOperator))
222        return new List<Type>();
223
224      // return only one type for ValueTypeValues<> (Int, Double, Percent, Bool). Otherwise 2 types would be returned for DoubleValue (PercentValue which is derived)
225      if (IsSubclassOfRawGeneric(typeof(ValueTypeValue<>), parameter.DataType))
226        return new List<Type> { parameter.DataType };
227     
228      if (IsSubclassOfRawGeneric(typeof(OptionalConstrainedValueParameter<>), parameter.GetType())) {
229        // use existing validvalues if known
230        var parameterValidValues = (IEnumerable)parameter.GetType().GetProperty("ValidValues").GetValue(parameter, new object[] { });
231        return parameterValidValues.Cast<object>().Select(x => x.GetType());
232      } else {
233        // otherwise use all assignable types
234        return ApplicationManager.Manager.GetTypes(parameter.DataType, true);
235      }
236    }
237
238    private IItemSet<IItem> GetValidValues(IValueParameter parameter) {
239      if (IsSubclassOfRawGeneric(typeof(OptionalConstrainedValueParameter<>), parameter.GetType())) {
240        var x = (IEnumerable)parameter.GetType().GetProperty("ValidValues").GetValue(parameter, new object[] { });
241        return new ItemSet<IItem>(x.Cast<IItem>().Select(y => (IItem)y.Clone())); // cloning actually saves memory, because references to event-subscribers are removed
242      } else {
243        return null;
244      }
245    }
246
247    public IItem CreateItem(Type type) {
248      // no valid values; just instantiate
249      if (validValues == null)
250        return (IItem)Activator.CreateInstance(type);
251
252      if (type == typeof(NullValue))
253        return new NullValue();
254     
255      // copy value from ValidValues; this ensures that previously set ActualNames for a type are kept
256      IItem value = this.validValues.Where(v => v.GetType() == type).SingleOrDefault();
257      if (value != null)
258        return value;
259
260      return null;
261    }
262
263    private IItemSet<IItem> CreateValidValues() {
264      var validValues = new ItemSet<IItem>();
265      foreach (Type t in this.validTypes) {
266        try {
267          var val = CreateItem(t);
268          validValues.Add(val);
269        }
270        catch (MissingMethodException) { /* Constructor is missing, don't use those types */ }
271      }
272      return validValues;
273    }
274
275    private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
276      while (toCheck != typeof(object)) {
277        var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
278        if (generic == cur) {
279          return true;
280        }
281        toCheck = toCheck.BaseType; // baseType is null when toCheck is an Interface
282        if (toCheck == null)
283          return false;
284      }
285      return false;
286    }
287
288    void ValueConfigurations_CheckedItemsChanged(object sender, Collections.CollectionItemsChangedEventArgs<IndexedItem<IValueConfiguration>> e) {
289      OnToStringChanged();
290    }
291    void ValueConfigurations_ItemsRemoved(object sender, Collections.CollectionItemsChangedEventArgs<IndexedItem<IValueConfiguration>> e) {
292      OnToStringChanged();
293    }
294    void ValueConfigurations_ItemsAdded(object sender, Collections.CollectionItemsChangedEventArgs<IndexedItem<IValueConfiguration>> e) {
295      OnToStringChanged();
296    }
297
298    #region INamedItem Properties
299    public virtual string Name {
300      get { return ParameterName; }
301      set { throw new NotSupportedException(); }
302    }
303    public virtual string Description {
304      get { return base.ItemDescription; }
305      set { throw new NotSupportedException(); }
306    }
307    public virtual bool CanChangeDescription {
308      get { return false; }
309    }
310    public virtual bool CanChangeName {
311      get { return false; }
312    }
313    public override string ItemDescription {
314      get { return base.ItemDescription; }
315    }
316    public override string ItemName {
317      get { return base.ItemName; }
318    }
319    #endregion
320
321    #region Events
322    void ActualValue_ToStringChanged(object sender, EventArgs e) {
323      OnToStringChanged();
324    }
325    #endregion
326
327    #region Event Handler
328    public virtual event EventHandler NameChanged;
329    protected virtual void OnNameChanged(object sender, EventArgs e) {
330      var handler = NameChanged;
331      if (handler != null) handler(sender, e);
332    }
333
334    public virtual event EventHandler<CancelEventArgs<string>> NameChanging;
335    protected virtual void OnNameChanging(object sender, CancelEventArgs<string> e) {
336      var handler = NameChanging;
337      if (handler != null) handler(sender, e);
338    }
339
340    public virtual event EventHandler DescriptionChanged;
341    protected virtual void OnDescriptionChanged(object sender, EventArgs e) {
342      var handler = DescriptionChanged;
343      if (handler != null) handler(sender, e);
344    }
345
346    public virtual event EventHandler IsOptimizableChanged;
347    private void OnIsOptimizableChanged() {
348      var handler = IsOptimizableChanged;
349      if (handler != null) handler(this, EventArgs.Empty);
350    }
351
352    public virtual event EventHandler OptimizeChanged;
353    protected virtual void OnOptimizeChanged() {
354      var handler = OptimizeChanged;
355      if (handler != null) handler(this, EventArgs.Empty);
356    }
357    #endregion
358
359    public override string ToString() {
360      if (Optimize) {
361        return string.Format("{0}: (Optimize: {1})", ParameterName, ValueConfigurations.CheckedItems.Count());
362      } else {
363        return string.Format("{0}: {1}", ParameterName, ActualValue.Value);
364      }
365    }
366
367    public string ParameterInfoString {
368      get {
369        StringBuilder sb = new StringBuilder();
370        if (this.Optimize) {
371          var vc = this.ValueConfigurations[actualValueConfigurationIndex];
372          if (IsSubclassOfRawGeneric(typeof(ValueTypeValue<>), vc.GetType())) {
373            // for int, double, bool use the value directly
374            sb.Append(string.Format("{0}: {1}", parameterName, this.ActualValue.Value != null ? this.ActualValue.Value.ToString() : "null"));
375          } else {
376            // for other types use NumberedName (this also uses the Number-Property for otherwise ambiguous ValueConfigurations)
377            sb.Append(string.Format("{0}: {1}", parameterName, vc.NumberedName));
378          }
379
380          if (this.ActualValue.Value is IParameterizedItem) {
381            string subParams = this.ValueConfigurations[actualValueConfigurationIndex].ParameterInfoString;
382            if (!string.IsNullOrEmpty(subParams)) {
383              sb.Append(" (");
384              sb.Append(subParams);
385              sb.Append(")");
386            }
387          }
388        }
389        return sb.ToString();
390      }
391    }
392
393    public static IParameterConfiguration Create(IParameterizedNamedItem parent, IParameter parameter) {
394      if (parameter is IValueParameter) {
395        IValueParameter valueParameter = parameter as IValueParameter;
396        return new ParameterConfiguration(parameter.Name, valueParameter);
397      }
398      return null;
399    }
400
401    public void Parameterize(IValueParameter parameter) {
402      if (Optimize) {
403        if (this.ActualValue.Value is IParameterizedItem) {
404          this.ValueConfigurations[actualValueConfigurationIndex].Parameterize((IParameterizedItem)this.ActualValue.Value);
405        }
406      }
407      var clonedValue = this.ActualValue.Value != null ? (IItem)this.ActualValue.Value.Clone() : null;
408      AdaptValidValues(parameter, clonedValue);
409      parameter.Value = clonedValue;
410    }
411
412    /// <summary>
413    /// Adds value to the ValidValues of the parameter if they don't contain the value
414    /// </summary>
415    private void AdaptValidValues(IValueParameter parameter, IItem value) {
416      // this requires some tricky reflection, because the type is unknown at runtime so parameter.ValidValues cannot be casted to Collection<?>
417      if (IsSubclassOfRawGeneric(typeof(OptionalConstrainedValueParameter<>), parameter.GetType())) {
418        var validValues = parameter.GetType().GetProperty("ValidValues").GetValue(parameter, new object[] { });
419        Type validValuesType = validValues.GetType();
420
421        var containsMethod = validValuesType.GetMethod("Contains");
422        if (!(bool)containsMethod.Invoke(validValues, new object[] { value })) {
423          var addMethod = validValuesType.GetMethod("Add");
424          addMethod.Invoke(validValues, new object[] { value });
425        }
426      }
427    }
428
429    public void Randomize(IRandom random) {
430      if (Optimize) {
431        foreach (var vc in this.ValueConfigurations) {
432          if (this.ValueConfigurations.ItemChecked(vc)) {
433            vc.Randomize(random);
434          }
435        }
436        do {
437          actualValueConfigurationIndex = random.Next(ValueConfigurations.Count());
438        } while (!this.ValueConfigurations.ItemChecked(this.ValueConfigurations[actualValueConfigurationIndex]));
439        this.ActualValue = this.ValueConfigurations[actualValueConfigurationIndex].ActualValue;
440      }
441    }
442
443    public void Mutate(IRandom random, MutateDelegate mutate, IIntValueManipulator intValueManipulator, IDoubleValueManipulator doubleValueManipulator) {
444      if (Optimize) {
445        foreach (var vc in this.ValueConfigurations) {
446          if (this.ValueConfigurations.ItemChecked(vc)) {
447            vc.Mutate(random, mutate, intValueManipulator, doubleValueManipulator);
448          }
449        }
450        mutate(random, this, intValueManipulator, doubleValueManipulator);
451      }
452    }
453
454    public void Cross(IRandom random, IOptimizable other, CrossDelegate cross, IIntValueCrossover intValueCrossover, IDoubleValueCrossover doubleValueCrossover) {
455      if (Optimize) {
456        IParameterConfiguration otherPc = (IParameterConfiguration)other;
457        for (int i = 0; i < this.ValueConfigurations.Count; i++) {
458          if (this.ValueConfigurations.ItemChecked(this.ValueConfigurations[i])) {
459            this.ValueConfigurations[i].Cross(random, otherPc.ValueConfigurations[i], cross, intValueCrossover, doubleValueCrossover);
460          }
461        }
462        cross(random, this, other, intValueCrossover, doubleValueCrossover);
463      }
464    }
465
466    public void UpdateActualValueIndexToItem(IValueConfiguration vc) {
467      for (int i = 0; i < this.ValueConfigurations.Count(); i++) {
468        if (this.ValueConfigurations.ElementAt(i) == vc) {
469          this.actualValueConfigurationIndex = i;
470          return;
471        }
472      }
473    }
474
475    public List<IOptimizable> GetAllOptimizables() {
476      var list = new List<IOptimizable>();
477      foreach (var vc in ValueConfigurations) {
478        if (vc.Optimize) {
479          list.Add(vc);
480          list.AddRange(vc.GetAllOptimizables());
481        }
482      }
483      return list;
484    }
485
486    public void CollectOptimizedParameterNames(List<string> parameterNames, string prefix) {
487      foreach (var vc in ValueConfigurations) {
488        if (vc.Optimize) {
489          vc.CollectOptimizedParameterNames(parameterNames, prefix);
490        }
491      }
492    }
493  }
494}
Note: See TracBrowser for help on using the repository browser.