using HeuristicLab.Operators; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HeuristicLab.Common; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Parameters; using HeuristicLab.Optimization; using HeuristicLab.PluginInfrastructure; using HeuristicLab.Analysis; namespace HeuristicLab.Algorithms.SimulatedAnnealing { [Item("RandomWalkReheatingOperator", "Performs a randomwalk with the lenght of n after x consecutive solutions were rejected.")] [StorableClass] public class RandomWalkReheatingOperator : SingleSuccessorOperator, IReheatingOperator { #region Strings private const string AnnealingOperatorName = "AnnealingOperator"; private const string LowerTemperatureName = "LowerTemperature"; private const string IterationsName = "Iterations"; private const string TemperatureStartIndexName = "TemperatureStartIndex"; private const string StartTemperatureName = "StartTemperature"; private const string EndTemperatureName = "EndTemperature"; private const string TemperatureName = "Temperature"; private const string MaximumIterationsName = "MaximumIterations"; private const string CurrentRandomWalkStepName = "CurrentRandomWalkStep"; private const string RandomWalkLengthName = "RandomWalkLength"; private const string ThresholdName = "Threshold"; private const string IsAcceptedName = "IsAccepted"; private const string ConsecutiveRejectedSolutionsCountName = "ConsecutiveRejectedSolutions"; private const string LastAcceptedQualityName = "LastAcceptedQuality"; private const string MoveQualityName = "MoveQuality"; private const string CoolingName = "Cooling"; #endregion #region Parameters public ILookupParameter TemperatureParameter { get { return (ILookupParameter)Parameters[TemperatureName]; } } public ILookupParameter LowerTemperatureParameter { get { return (ILookupParameter)Parameters[LowerTemperatureName]; } } public ILookupParameter StartTemperatureParameter { get { return (ILookupParameter)Parameters[StartTemperatureName]; } } public ILookupParameter EndTemperatureParameter { get { return (ILookupParameter)Parameters[EndTemperatureName]; } } public ILookupParameter TemperatureStartIndexParameter { get { return (ILookupParameter)Parameters[TemperatureStartIndexName]; } } public ILookupParameter IterationsParameter { get { return (ILookupParameter)Parameters[IterationsName]; } } public ILookupParameter AnnealingOperatorParameter { get { return (ILookupParameter)Parameters[AnnealingOperatorName]; } } public ILookupParameter MaximumIterationsParameter { get { return (ILookupParameter)Parameters[MaximumIterationsName]; } } private ValueParameter ThresholdParameter { get { return (ValueParameter)Parameters[ThresholdName]; } } private ValueParameter RandomWalkLengthParameter { get { return (ValueParameter)Parameters[RandomWalkLengthName]; } } public ILookupParameter IsAcceptedParameter { get { return (ILookupParameter)Parameters[IsAcceptedName]; } } public ILookupParameter ConsecutiveRejectedSolutionsCountParameter { get { return (ILookupParameter)Parameters[ConsecutiveRejectedSolutionsCountName]; } } public ILookupParameter RandomWalkLengthNameParameter { get { return (ILookupParameter)Parameters[RandomWalkLengthName]; } } public ILookupParameter CurrentRandomWalkStepParameter { get { return (ILookupParameter)Parameters[CurrentRandomWalkStepName]; } } public ILookupParameter CoolingParameter { get { return (ILookupParameter)Parameters[CoolingName]; } } public ILookupParameter MoveQualityParameter { get { return (ILookupParameter)Parameters[MoveQualityName]; } } public ILookupParameter LastAcceptedQualityParameter { get { return (ILookupParameter)Parameters[LastAcceptedQualityName]; } } #endregion public RandomWalkReheatingOperator() : base() { #region Create parameters Parameters.Add(new LookupParameter(TemperatureName, "The current temperature.")); Parameters.Add(new LookupParameter(LowerTemperatureName, "The lower bound of the temperature.")); Parameters.Add(new LookupParameter(IterationsName, "The number of iterations.")); Parameters.Add(new LookupParameter(AnnealingOperatorName, "The operator that cools the temperature.")); Parameters.Add(new LookupParameter(TemperatureStartIndexName, "The index where the annealing or heating was last changed.")); Parameters.Add(new LookupParameter(StartTemperatureName, "The temperature from which cooling or reheating should occur.")); Parameters.Add(new LookupParameter(EndTemperatureName, "The temperature to which should be cooled or heated.")); Parameters.Add(new LookupParameter(MaximumIterationsName, "The maximum number of iterations which should be processed.")); Parameters.Add(new LookupParameter(IsAcceptedName, "Whether the move was accepted or not.")); Parameters.Add(new LookupParameter(ConsecutiveRejectedSolutionsCountName, "Amount of consecutive rejected solutions.")); Parameters.Add(new ValueParameter(ThresholdName, "How many consecutive rejected solutions must occur to trigger a reheat.", new IntValue(10000))); Parameters.Add(new ValueParameter(RandomWalkLengthName, "Amount of randomly accepted moves upon reheat.", new IntValue(1))); Parameters.Add(new LookupParameter(CurrentRandomWalkStepName, "Current random walk step.")); Parameters.Add(new LookupParameter(MoveQualityName, "The value which represents the quality of a move.")); Parameters.Add(new LookupParameter(CoolingName, "True when the temperature should be cooled, false otherwise.")); Parameters.Add(new LookupParameter(LastAcceptedQualityName, "Quality of last accepted solution.")); #endregion Parameterize(); } [StorableConstructor] protected RandomWalkReheatingOperator(bool deserializing) : base(deserializing) { } protected RandomWalkReheatingOperator(RandomWalkReheatingOperator original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new RandomWalkReheatingOperator(this, cloner); } public void Parameterize() { } public override IOperation Apply() { var cooling = CoolingParameter.ActualValue.Value; var quality = MoveQualityParameter.ActualValue; var lastAcceptedQuality = LastAcceptedQualityParameter.ActualValue; var isAccepted = IsAcceptedParameter.ActualValue.Value; var consecutiveRejectedSolutionsCount = ConsecutiveRejectedSolutionsCountParameter.ActualValue; if (cooling) { // add acceptance value to consecutive rejected solutions count // if quality hasnt changed, we might be stuck on a plateau if (!isAccepted || quality.Value.Equals(lastAcceptedQuality.Value)) { consecutiveRejectedSolutionsCount.Value++; } else { consecutiveRejectedSolutionsCount.Value = 0; } // check if we are trapped in a local optimum if (consecutiveRejectedSolutionsCount.Value >= ThresholdParameter.Value.Value) { cooling = false; consecutiveRejectedSolutionsCount.Value = 0; } } if (!cooling) { // random walk finished, start cooling again if (RandomWalkLengthParameter.Value.Value <= CurrentRandomWalkStepParameter.ActualValue.Value) { cooling = true; CurrentRandomWalkStepParameter.ActualValue.Value = 0; } else { CurrentRandomWalkStepParameter.ActualValue.Value++; } } if (isAccepted) { LastAcceptedQualityParameter.ActualValue.Value = quality.Value; } CoolingParameter.ActualValue.Value = cooling; return cooling ? Cool() : Heat(); } private IOperation Heat() { TemperatureParameter.ActualValue.Value = Double.PositiveInfinity; return base.Apply(); } private IOperation Cool() { return new OperationCollection { ExecutionContext.CreateOperation(AnnealingOperatorParameter.ActualValue), base.Apply() }; } } }