using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.MetaOptimization { [StorableClass] public abstract class Range : Item, IRange where T : class, IItem, IStringConvertibleValue, IDeepCloneable { [Storable] private T lowerBound; public virtual T LowerBound { get { return lowerBound; } set { if (lowerBound != value) { if (lowerBound != null) { lowerBound.ValueChanged -= new EventHandler(lowerBound_ToStringChanged); } lowerBound = value; if (lowerBound != null) { lowerBound.ValueChanged += new EventHandler(lowerBound_ToStringChanged); } OnLowerBoundChanged(); } } } [Storable] private T upperBound; public virtual T UpperBound { get { return upperBound; } set { if (upperBound != value) { if (upperBound != null) { upperBound.ValueChanged -= new EventHandler(upperBound_ToStringChanged); } upperBound = value; if (upperBound != null) { upperBound.ValueChanged += new EventHandler(upperBound_ToStringChanged); } OnUpperBoundChanged(); } } } [Storable] private T stepSize; public virtual T StepSize { get { return stepSize; } set { if (stepSize != value) { if (stepSize != null) { stepSize.ValueChanged -= new EventHandler(stepSize_ToStringChanged); } stepSize = value; if (stepSize != null) { stepSize.ValueChanged += new EventHandler(stepSize_ToStringChanged); } OnStepSizeChanged(); } } } #region IRange Members object IRange.LowerBound { get { return lowerBound; } set { lowerBound = (T)value; } } object IRange.UpperBound { get { return upperBound; } set { upperBound = (T)value; } } object IRange.StepSize { get { return stepSize; } set { stepSize = (T)value; } } #endregion #region Constructors and Cloning public Range(T lowerBound, T upperBound, T stepSize) { this.LowerBound = lowerBound; this.UpperBound = upperBound; this.StepSize = stepSize; } [StorableConstructor] protected Range(bool deserializing) : base(deserializing) { } protected Range(Range original, Cloner cloner) : base(original, cloner) { this.LowerBound = cloner.Clone(original.LowerBound); this.UpperBound = cloner.Clone(original.UpperBound); this.StepSize = cloner.Clone(original.StepSize); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (lowerBound != null) { lowerBound.ValueChanged += new EventHandler(lowerBound_ToStringChanged); } if (upperBound != null) { upperBound.ValueChanged += new EventHandler(upperBound_ToStringChanged); } if (stepSize != null) { stepSize.ValueChanged += new EventHandler(stepSize_ToStringChanged); } } #endregion #region Events private void lowerBound_ToStringChanged(object sender, EventArgs e) { OnToStringChanged(); } private void upperBound_ToStringChanged(object sender, EventArgs e) { OnToStringChanged(); } private void stepSize_ToStringChanged(object sender, EventArgs e) { OnToStringChanged(); } #endregion #region Eventhandler public event EventHandler LowerBoundChanged; private void OnLowerBoundChanged() { var handler = LowerBoundChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler UpperBoundChanged; private void OnUpperBoundChanged() { var handler = UpperBoundChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler StepSizeChanged; private void OnStepSizeChanged() { var handler = StepSizeChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler ValueChanged; private void OnValueChanged() { var handler = ValueChanged; if (handler != null) handler(this, EventArgs.Empty); } #endregion public override string ToString() { return string.Format("{0},{1}:{2}", LowerBound.ToString(), UpperBound.ToString(), StepSize.ToString()); } #region IStringConvertibleValue Members public string GetValue() { return this.ToString(); } public bool ReadOnly { get { return false; } } public bool SetValue(string value) { var parts1 = value.Split(':'); if (parts1.Length != 2) return false; var parts2 = parts1[0].Split(','); if (parts2.Length != 2) return false; return lowerBound.SetValue(parts2[0]) && upperBound.SetValue(parts2[1]) && stepSize.SetValue(parts1[1]); } public bool Validate(string value, out string errorMessage) { // TODO: check that upper is larger than lower and that stepsize < upper-lower T lower = (T)lowerBound.Clone(); T upper = (T)upperBound.Clone(); T step = (T)stepSize.Clone(); var parts1 = value.Split(':'); if (parts1.Length != 2) { errorMessage = "Could not parse range."; return false; } var parts2 = parts1[0].Split(','); if (parts2.Length != 2) { errorMessage = "Could not parse range."; return false; } if (lowerBound.SetValue(parts2[0]) && upperBound.SetValue(parts2[1]) && stepSize.SetValue(parts1[1])) { errorMessage = string.Empty; return true; } else { errorMessage = "Could not parse range."; return false; } } #endregion public T GetRandomValue(IRandom random) { // by a chance return the extreme values of this range to intensify search in those regions if (random.NextDouble() < 0.1) { if (random.NextDouble() < 0.5) { return (T)LowerBound.Clone(); } else { return (T)UpperBound.Clone(); } } // otherwise sample a random value from the range return GetRandomSample(random); } protected abstract T GetRandomSample(IRandom random); IItem IRange.GetRandomValue(IRandom random) { return GetRandomValue(random); } public abstract IEnumerable GetCombinations(); IEnumerable IRange.GetCombinations() { return GetCombinations().Cast().ToArray(); } public virtual double CalculateSimilarity(IItem a, IItem b) { return CalculateSimilarityValue((T)a, (T)b); } protected abstract double CalculateSimilarityValue(T a, T b); } }