Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1215

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