Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1215

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