#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.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Operators;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Algorithms.SimulatedAnnealing {
[Item("TemperatureController", "Decides whether to use cooling or heating and calls the appropriate operator.")]
[StorableClass]
public class TemperatureController : SingleSuccessorOperator {
#region Strings
private const string AnnealingOperatorName = "AnnealingOperator";
private const string HeatingOperatorName = "HeatingOperator";
private const string MaximumIterationsName = "MaximumIterations";
private const string UpperTemperatureName = "UpperTemperature";
private const string LowerTemperatureName = "LowerTemperature";
private const string IterationsName = "Iterations";
private const string TemperatureStartIndexName = "TemperatureStartIndex";
private const string CoolingName = "Cooling";
private const string StartTemperatureName = "StartTemperature";
private const string EndTemperatureName = "EndTemperature";
private const string TemperatureName = "Temperature";
private const string IsAcceptedName = "IsAccepted";
private const string ThresholdName = "Threshold";
private const string AcceptanceMemoryName = "AcceptanceMemory";
private const string MemorySizeName = "MemorySize";
#endregion
#region Parameter Properties
public ILookupParameter TemperatureParameter {
get { return (ILookupParameter)Parameters[TemperatureName]; }
}
public IValueLookupParameter UpperTemperatureParameter {
get { return (IValueLookupParameter)Parameters[UpperTemperatureName]; }
}
public IValueLookupParameter LowerTemperatureParameter {
get { return (IValueLookupParameter)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 CoolingParameter {
get { return (ILookupParameter)Parameters[CoolingName]; }
}
public ILookupParameter IterationsParameter {
get { return (ILookupParameter)Parameters[IterationsName]; }
}
public IValueLookupParameter MaximumIterationsParameter {
get { return (IValueLookupParameter)Parameters[MaximumIterationsName]; }
}
public IValueLookupParameter AnnealingOperatorParameter {
get { return (IValueLookupParameter)Parameters[AnnealingOperatorName]; }
}
public IValueLookupParameter HeatingOperatorParameter {
get { return (IValueLookupParameter)Parameters[HeatingOperatorName]; }
}
public ILookupParameter IsAcceptedParameter {
get { return (ILookupParameter)Parameters[IsAcceptedName]; }
}
public IValueLookupParameter ThresholdParameter {
get { return (IValueLookupParameter)Parameters[ThresholdName]; }
}
public ILookupParameter> AcceptanceMemoryParameter {
get { return (ILookupParameter>)Parameters[AcceptanceMemoryName]; }
}
public IValueLookupParameter MemorySizeParameter {
get { return (IValueLookupParameter)Parameters[MemorySizeName]; }
}
#endregion
[StorableConstructor]
protected TemperatureController(bool deserializing) : base(deserializing) {}
protected TemperatureController(TemperatureController original, Cloner cloner) : base(original, cloner) {}
public TemperatureController()
: base() {
Parameters.Add(new LookupParameter(TemperatureName, "The current temperature."));
Parameters.Add(new ValueLookupParameter(UpperTemperatureName, "The upper bound of the temperature."));
Parameters.Add(new ValueLookupParameter(LowerTemperatureName, "The lower bound of the temperature."));
Parameters.Add(new LookupParameter(IterationsName, "The number of iterations."));
Parameters.Add(new ValueLookupParameter(MaximumIterationsName, "The maximum number of iterations which should be processed."));
Parameters.Add(new ValueLookupParameter(AnnealingOperatorName, "The operator that cools the temperature."));
Parameters.Add(new ValueLookupParameter(HeatingOperatorName, "The operator that heats the temperature."));
Parameters.Add(new LookupParameter(TemperatureStartIndexName, "The index where the annealing or heating was last changed."));
Parameters.Add(new LookupParameter(CoolingName, "True when the temperature should be cooled, false otherwise."));
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(IsAcceptedName, "Whether the move was accepted or not."));
Parameters.Add(new ValueLookupParameter(ThresholdName, "The threshold controls the temperature in case a heating operator is specified. If the average ratio of accepted moves goes below the start of the range the temperature is heated. If the the average ratio of accepted moves goes beyond the end of the range the temperature is cooled again."));
Parameters.Add(new LookupParameter>(AcceptanceMemoryName, "Memorizes the last N acceptance decisions."));
Parameters.Add(new ValueLookupParameter(MemorySizeName, "The maximum size of the acceptance memory."));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new TemperatureController(this, cloner);
}
public override IOperation Apply() {
var accepted = IsAcceptedParameter.ActualValue;
var heatingOperator = HeatingOperatorParameter.ActualValue;
if (accepted == null || heatingOperator == null) { // perform only annealing in case no heating operator is given
return new OperationCollection {
ExecutionContext.CreateOperation(AnnealingOperatorParameter.ActualValue),
base.Apply()
};
}
var cooling = CoolingParameter.ActualValue.Value;
var iterations = IterationsParameter.ActualValue.Value;
var ratioStart = ThresholdParameter.ActualValue.Start;
var ratioEnd = ThresholdParameter.ActualValue.End;
var acceptances = AcceptanceMemoryParameter.ActualValue;
acceptances.Add(new BoolValue(accepted.Value));
if (acceptances.Count > MemorySizeParameter.ActualValue.Value) acceptances.RemoveAt(0);
var ratio = acceptances.Average(x => x.Value ? 1.0 : 0.0);
if (!cooling && ratio >= ratioEnd) { // temperature is heated, but should be cooled
cooling = true;
TemperatureStartIndexParameter.ActualValue.Value = Math.Max(0, iterations - 1);
StartTemperatureParameter.ActualValue.Value = TemperatureParameter.ActualValue.Value;
EndTemperatureParameter.ActualValue.Value = LowerTemperatureParameter.ActualValue.Value;
} else if (cooling && ratio <= ratioStart) { // temperature is cooled, but should be heated
cooling = false;
TemperatureStartIndexParameter.ActualValue.Value = Math.Max(0, iterations - 1);
StartTemperatureParameter.ActualValue.Value = TemperatureParameter.ActualValue.Value;
EndTemperatureParameter.ActualValue.Value = UpperTemperatureParameter.ActualValue.Value;
}
CoolingParameter.ActualValue.Value = cooling;
if (cooling) {
return new OperationCollection {
ExecutionContext.CreateOperation(AnnealingOperatorParameter.ActualValue),
base.Apply()
};
}
// heating
return new OperationCollection {
ExecutionContext.CreateOperation(HeatingOperatorParameter.ActualValue),
base.Apply()
};
}
}
}