#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.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Encodings.ParameterConfigurationEncoding {
[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_ValueChanged);
lowerBound.ValueChanged -= new EventHandler(lowerBound_ToStringChanged);
}
lowerBound = value;
if (lowerBound != null) {
lowerBound.ValueChanged += new EventHandler(lowerBound_ValueChanged);
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_ValueChanged);
upperBound.ValueChanged -= new EventHandler(upperBound_ToStringChanged);
}
upperBound = value;
if (upperBound != null) {
upperBound.ValueChanged += new EventHandler(upperBound_ValueChanged);
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_ValueChanged);
stepSize.ValueChanged -= new EventHandler(stepSize_ToStringChanged);
}
stepSize = value;
if (stepSize != null) {
stepSize.ValueChanged += new EventHandler(stepSize_ValueChanged);
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
[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);
}
public Range(T lowerBound, T upperBound, T stepSize)
: base() {
this.LowerBound = lowerBound;
this.UpperBound = upperBound;
this.StepSize = stepSize;
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (lowerBound != null) {
lowerBound.ValueChanged += new EventHandler(lowerBound_ValueChanged);
lowerBound.ValueChanged += new EventHandler(lowerBound_ToStringChanged);
}
if (upperBound != null) {
upperBound.ValueChanged += new EventHandler(upperBound_ValueChanged);
upperBound.ValueChanged += new EventHandler(upperBound_ToStringChanged);
}
if (stepSize != null) {
stepSize.ValueChanged += new EventHandler(stepSize_ValueChanged);
stepSize.ValueChanged += new EventHandler(stepSize_ToStringChanged);
}
}
#endregion
#region Events
private void lowerBound_ValueChanged(object sender, EventArgs e) {
OnLowerBoundChanged();
}
private void upperBound_ValueChanged(object sender, EventArgs e) {
OnUpperBoundChanged();
}
private void stepSize_ValueChanged(object sender, EventArgs e) {
OnStepSizeChanged();
}
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) {
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])) {
if (Comparer.Default.Compare(lowerBound, upperBound) >= 0) {
errorMessage = "Invalid bounds. (Lower >= Upper)"; return false;
}
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);
}
}