#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using HeuristicLab.Collections;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Encodings.ParameterConfigurationTreeEncoding {
[StorableClass]
public class ParameterConfiguration : Item, IParameterConfiguration, IStorableContent {
public bool IsOptimizable {
get { return true; }
}
public string Filename { get; set; }
[Storable]
protected bool optimize;
public virtual bool Optimize {
get { return optimize; }
set {
if (optimize != value) {
optimize = value;
if (optimize) {
PopulateValueConfigurations();
} else {
ClearValueConfigurations();
}
OnOptimizeChanged();
OnToStringChanged();
}
}
}
[Storable]
protected Image itemImage;
public override Image ItemImage {
get { return itemImage ?? base.ItemImage; }
}
[Storable]
protected string parameterName;
public string ParameterName {
get { return parameterName; }
set {
if (parameterName != value) {
parameterName = value;
OnToStringChanged();
}
}
}
[Storable]
protected Type parameterDataType;
public Type ParameterDataType {
get { return this.parameterDataType; }
}
protected Type[] validTypes;
public Type[] ValidTypes {
get { return validTypes; }
protected set {
if (this.validTypes != value) {
this.validTypes = value;
}
}
}
[Storable]
protected Type valueDataType;
public Type ValueDataType {
get { return valueDataType; }
protected set { this.valueDataType = value; }
}
[Storable]
protected ICheckedValueConfigurationList valueConfigurations;
public ICheckedValueConfigurationList ValueConfigurations {
get { return this.valueConfigurations; }
protected set {
if (this.valueConfigurations != value) {
if (this.valueConfigurations != null) DeregisterValueConfigurationEvents();
this.valueConfigurations = value;
KeepActualValueConfigurationIndexConsistent();
if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
}
}
}
[Storable]
private int actualValueConfigurationIndex = 0;
public int ActualValueConfigurationIndex {
get { return actualValueConfigurationIndex; }
set { actualValueConfigurationIndex = value; }
}
[Storable]
protected ConstrainedValue actualValue;
public ConstrainedValue ActualValue {
get { return actualValue; }
set {
if (actualValue != value) {
DeregisterActualValueEvents();
actualValue = value;
RegisterActualValueEvents();
}
}
}
[Storable]
protected bool isNullable;
public bool IsNullable {
get { return isNullable; }
protected set {
if (this.isNullable != value) {
this.isNullable = value;
}
}
}
[Storable]
protected bool discoverValidValues;
public bool DiscoverValidValues {
get { return discoverValidValues; }
set { discoverValidValues = value; }
}
protected IItemSet validValues;
[Storable]
private bool autoPopulateValueConfigurations = true;
public bool AutoPopulateValueConfigurations {
get { return autoPopulateValueConfigurations; }
set { autoPopulateValueConfigurations = value; }
}
[Storable]
protected bool valuesReadOnly = false;
public virtual bool ValuesReadOnly {
get { return valuesReadOnly; }
set {
if (value != this.valuesReadOnly) {
this.valuesReadOnly = value;
foreach (var vc in this.valueConfigurations) {
vc.ValuesReadOnly = value;
}
}
}
}
#region Constructors and Cloning
public ParameterConfiguration(string parameterName, IValueParameter valueParameter, bool discoverValidValues) {
this.AutoPopulateValueConfigurations = true;
this.ParameterName = parameterName;
this.parameterDataType = valueParameter.GetType();
this.valueDataType = valueParameter.DataType;
this.discoverValidValues = discoverValidValues;
this.validValues = discoverValidValues ? GetValidValues(valueParameter) : new ItemSet { valueParameter.Value };
this.validTypes = GetValidTypes(valueParameter).ToArray();
this.IsNullable = valueParameter.ItemName.StartsWith("Optional");
this.itemImage = valueParameter.ItemImage;
if (IsNullable) {
validTypes = new List(validTypes) { typeof(NullValue) }.ToArray();
}
this.ValueConfigurations = new CheckedValueConfigurationList(this.validValues ?? CreateValidValues());
this.ActualValue = new ConstrainedValue(
valueParameter.Value != null ? valueParameter.Value : null, // don't clone here; otherwise settings of a non-optimized ValueParameter will not be synchronized with the ConstrainedValue
valueParameter.DataType,
this.validValues != null ? new ItemSet(this.validValues) : CreateValidValues(),
this.IsNullable);
if (Optimize) {
PopulateValueConfigurations();
}
}
public ParameterConfiguration(string parameterName, Type type, IItem actualValue, IEnumerable valueConfigurations) {
this.AutoPopulateValueConfigurations = false;
this.ParameterName = parameterName;
this.parameterDataType = type;
this.valueDataType = type;
this.discoverValidValues = false;
this.validValues = null; // maybe use values from valueConfigurations
this.validTypes = new Type[] { type };
this.IsNullable = false;
this.itemImage = valueConfigurations.Count() > 0 ? valueConfigurations.FirstOrDefault().ItemImage : null;
this.ValueConfigurations = new CheckedValueConfigurationList(valueConfigurations);
this.ActualValue = new ConstrainedValue(actualValue, type, CreateValidValues(), this.IsNullable);
}
public ParameterConfiguration(string parameterName, Type type, IItem actualValue) {
this.AutoPopulateValueConfigurations = true;
this.ParameterName = parameterName;
this.parameterDataType = type;
this.valueDataType = type;
this.discoverValidValues = false;
this.validValues = null;
this.validTypes = new Type[] { type };
this.IsNullable = false;
this.itemImage = actualValue.ItemImage;
this.ValueConfigurations = new CheckedValueConfigurationList();
this.ActualValue = new ConstrainedValue(actualValue, type, CreateValidValues(), this.IsNullable);
if (Optimize) {
PopulateValueConfigurations();
}
}
public ParameterConfiguration() { }
[StorableConstructor]
protected ParameterConfiguration(bool deserializing) { }
protected ParameterConfiguration(ParameterConfiguration original, Cloner cloner)
: base(original, cloner) {
this.parameterName = original.ParameterName;
this.parameterDataType = original.parameterDataType;
this.valueDataType = original.ValueDataType;
this.validValues = cloner.Clone(original.validValues);
this.validTypes = original.validTypes.ToArray();
this.valueConfigurations = cloner.Clone(original.ValueConfigurations);
if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
this.actualValue = cloner.Clone(original.actualValue);
if (this.actualValue != null) RegisterActualValueEvents();
this.optimize = original.optimize;
this.actualValueConfigurationIndex = original.actualValueConfigurationIndex;
this.isNullable = original.isNullable;
this.itemImage = original.itemImage;
this.discoverValidValues = original.discoverValidValues;
this.AutoPopulateValueConfigurations = original.AutoPopulateValueConfigurations;
this.valuesReadOnly = original.valuesReadOnly;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ParameterConfiguration(this, cloner);
}
[StorableHook(HookType.AfterDeserialization)]
protected virtual void AfterDeserialization() {
this.validTypes = GetValidTypes(parameterDataType).ToArray();
if (IsNullable) {
validTypes = new List(validTypes) { typeof(NullValue) }.ToArray();
}
this.validValues = CreateValidValues();
if (this.valueConfigurations != null) RegisterValueConfigurationEvents();
if (this.actualValue != null) RegisterActualValueEvents();
}
#endregion
private void RegisterValueConfigurationEvents() {
this.ValueConfigurations.CheckedItemsChanged += new CollectionItemsChangedEventHandler>(ValueConfigurations_CheckedItemsChanged);
this.ValueConfigurations.ItemsAdded += new CollectionItemsChangedEventHandler>(ValueConfigurations_ItemsAdded);
this.ValueConfigurations.ItemsRemoved += new CollectionItemsChangedEventHandler>(ValueConfigurations_ItemsRemoved);
}
private void DeregisterValueConfigurationEvents() {
this.ValueConfigurations.CheckedItemsChanged -= new CollectionItemsChangedEventHandler>(ValueConfigurations_CheckedItemsChanged);
this.ValueConfigurations.ItemsAdded -= new CollectionItemsChangedEventHandler>(ValueConfigurations_ItemsAdded);
this.ValueConfigurations.ItemsRemoved -= new CollectionItemsChangedEventHandler>(ValueConfigurations_ItemsRemoved);
}
private void RegisterActualValueEvents() {
if (this.ActualValue != null) this.ActualValue.ToStringChanged += new EventHandler(ActualValue_ToStringChanged);
}
private void DeregisterActualValueEvents() {
if (this.ActualValue != null) this.ActualValue.ToStringChanged -= new EventHandler(ActualValue_ToStringChanged);
}
protected virtual void PopulateValueConfigurations() {
if (!this.AutoPopulateValueConfigurations)
return;
foreach (Type t in this.validTypes) {
if (t == typeof(NullValue)) {
this.ValueConfigurations.Add(new NullValueConfiguration());
} else {
IItem val;
if (ActualValue.Value != null && ActualValue.Value.GetType() == t) {
val = (IItem)ActualValue.Value.Clone(); // use existing value for that type (if available)
} else {
val = CreateItem(t);
}
if (val != null) { // val can be null when ValidValues does not contain the type (this can happen when discoverValidValues=false)
IValueConfiguration valueConfiguration;
if (val is IParameterizedItem) {
valueConfiguration = new ParameterizedValueConfiguration(val, val.GetType(), true);
} else {
if (val is ISymbolicExpressionGrammar) {
valueConfiguration = new SymbolicExpressionGrammarValueConfiguration((ISymbolicExpressionGrammar)val);
} else {
valueConfiguration = new RangeValueConfiguration(val, val.GetType());
}
}
this.ValueConfigurations.Add(valueConfiguration, true);
}
}
}
}
protected virtual void ClearValueConfigurations() {
if (!this.AutoPopulateValueConfigurations)
return;
this.ValueConfigurations.Clear();
}
private static IEnumerable GetValidTypes(IValueParameter parameter) {
// in case of IOperator return empty list, otherwise hundreds of types would be returned. this mostly occurs for Successor which will never be optimized
if (parameter.DataType == typeof(IOperator))
return new List();
// return only one type for ValueTypeValues<> (Int, Double, Percent, Bool). Otherwise 2 types would be returned for DoubleValue (PercentValue which is derived)
if (IsSubclassOfRawGeneric(typeof(ValueTypeValue<>), parameter.DataType))
return new List { parameter.DataType };
if (IsSubclassOfRawGeneric(typeof(OptionalConstrainedValueParameter<>), parameter.GetType())) {
// use existing validvalues if known
var parameterValidValues = (IEnumerable)parameter.GetType().GetProperty("ValidValues").GetValue(parameter, new object[] { });
return parameterValidValues.Cast