Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1215

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