1 | using HeuristicLab.Operators;
|
---|
2 | using System;
|
---|
3 | using System.Collections.Generic;
|
---|
4 | using System.Linq;
|
---|
5 | using System.Text;
|
---|
6 | using System.Threading.Tasks;
|
---|
7 | using HeuristicLab.Common;
|
---|
8 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
9 | using HeuristicLab.Core;
|
---|
10 | using HeuristicLab.Data;
|
---|
11 | using HeuristicLab.Parameters;
|
---|
12 | using HeuristicLab.Optimization;
|
---|
13 | using HeuristicLab.PluginInfrastructure;
|
---|
14 | using HeuristicLab.Analysis;
|
---|
15 |
|
---|
16 | namespace HeuristicLab.Algorithms.SimulatedAnnealing
|
---|
17 | {
|
---|
18 | [Item("AcceptanceRatioReheatingOperator", "Reheats the temperature if the acceptance is below a threshold until it is above another one.")]
|
---|
19 | [StorableClass]
|
---|
20 | public class AcceptanceRatioReheatingOperator : SingleSuccessorOperator, IReheatingOperator
|
---|
21 | {
|
---|
22 | #region Strings
|
---|
23 | private const string AnnealingOperatorName = "AnnealingOperator";
|
---|
24 | private const string LowerTemperatureName = "LowerTemperature";
|
---|
25 | private const string IterationsName = "Iterations";
|
---|
26 | private const string TemperatureStartIndexName = "TemperatureStartIndex";
|
---|
27 | private const string StartTemperatureName = "StartTemperature";
|
---|
28 | private const string EndTemperatureName = "EndTemperature";
|
---|
29 | private const string TemperatureName = "Temperature";
|
---|
30 | private const string MaximumIterationsName = "MaximumIterations";
|
---|
31 |
|
---|
32 | private const string UpperTemperatureName = "UpperTemperature";
|
---|
33 | private const string ReheatingOperatorName = "ReheatingOperator";
|
---|
34 | private const string ThresholdName = "Threshold";
|
---|
35 | private const string MemorySizeName = "MemorySize";
|
---|
36 | private const string CoolingName = "Cooling";
|
---|
37 | private const string IsAcceptedName = "IsAccepted";
|
---|
38 | private const string AcceptanceMemoryName = "AcceptanceMemory";
|
---|
39 | private const string AverageAcceptanceRatioName = "AverageAcceptanceRatio";
|
---|
40 | private const string ReheatWindowSizeName = "ReheatWindowSize";
|
---|
41 | private const string LastAcceptedQualityName = "LastAcceptedQuality";
|
---|
42 | private const string MoveQualityName = "MoveQuality";
|
---|
43 |
|
---|
44 |
|
---|
45 | #endregion
|
---|
46 | #region Parameters
|
---|
47 | public ILookupParameter<DoubleValue> TemperatureParameter
|
---|
48 | {
|
---|
49 | get { return (ILookupParameter<DoubleValue>)Parameters[TemperatureName]; }
|
---|
50 | }
|
---|
51 | public ILookupParameter<DoubleValue> LowerTemperatureParameter
|
---|
52 | {
|
---|
53 | get { return (ILookupParameter<DoubleValue>)Parameters[LowerTemperatureName]; }
|
---|
54 | }
|
---|
55 | public ILookupParameter<DoubleValue> StartTemperatureParameter
|
---|
56 | {
|
---|
57 | get { return (ILookupParameter<DoubleValue>)Parameters[StartTemperatureName]; }
|
---|
58 | }
|
---|
59 | public ILookupParameter<DoubleValue> EndTemperatureParameter
|
---|
60 | {
|
---|
61 | get { return (ILookupParameter<DoubleValue>)Parameters[EndTemperatureName]; }
|
---|
62 | }
|
---|
63 | public ILookupParameter<IntValue> TemperatureStartIndexParameter
|
---|
64 | {
|
---|
65 | get { return (ILookupParameter<IntValue>)Parameters[TemperatureStartIndexName]; }
|
---|
66 | }
|
---|
67 | public ILookupParameter<IntValue> IterationsParameter
|
---|
68 | {
|
---|
69 | get { return (ILookupParameter<IntValue>)Parameters[IterationsName]; }
|
---|
70 | }
|
---|
71 | public ILookupParameter<IDiscreteDoubleValueModifier> AnnealingOperatorParameter
|
---|
72 | {
|
---|
73 | get { return (ILookupParameter<IDiscreteDoubleValueModifier>)Parameters[AnnealingOperatorName]; }
|
---|
74 | }
|
---|
75 | public ILookupParameter<IntValue> MaximumIterationsParameter
|
---|
76 | {
|
---|
77 | get { return (ILookupParameter<IntValue>)Parameters[MaximumIterationsName]; }
|
---|
78 | }
|
---|
79 | private ValueLookupParameter<DoubleValue> UpperTemperatureParameter
|
---|
80 | {
|
---|
81 | get { return (ValueLookupParameter<DoubleValue>)Parameters[UpperTemperatureName]; }
|
---|
82 | }
|
---|
83 | private IConstrainedValueParameter<IDiscreteDoubleValueModifier> ReheatingOperatorParameter
|
---|
84 | {
|
---|
85 | get { return (IConstrainedValueParameter<IDiscreteDoubleValueModifier>)Parameters[ReheatingOperatorName]; }
|
---|
86 | }
|
---|
87 | private ValueParameter<DoubleRange> ThresholdParameter
|
---|
88 | {
|
---|
89 | get { return (ValueParameter<DoubleRange>)Parameters[ThresholdName]; }
|
---|
90 | }
|
---|
91 | private ValueParameter<IntValue> MemorySizeParameter
|
---|
92 | {
|
---|
93 | get { return (ValueParameter<IntValue>)Parameters[MemorySizeName]; }
|
---|
94 | }
|
---|
95 | public ILookupParameter<BoolValue> CoolingParameter
|
---|
96 | {
|
---|
97 | get { return (ILookupParameter<BoolValue>)Parameters[CoolingName]; }
|
---|
98 | }
|
---|
99 | public ILookupParameter<BoolValue> IsAcceptedParameter
|
---|
100 | {
|
---|
101 | get { return (ILookupParameter<BoolValue>)Parameters[IsAcceptedName]; }
|
---|
102 | }
|
---|
103 | public ILookupParameter<ItemList<BoolValue>> AcceptanceMemoryParameter
|
---|
104 | {
|
---|
105 | get { return (ILookupParameter<ItemList<BoolValue>>)Parameters[AcceptanceMemoryName]; }
|
---|
106 | }
|
---|
107 | public ILookupParameter<DoubleValue> AverageAcceptanceRatioParameter
|
---|
108 | {
|
---|
109 | get { return (ILookupParameter<DoubleValue>)Parameters[AverageAcceptanceRatioName]; }
|
---|
110 | }
|
---|
111 | public IValueParameter<IntValue> ReheatWindowSizeParameter
|
---|
112 | {
|
---|
113 | get { return (IValueParameter<IntValue>)Parameters[ReheatWindowSizeName]; }
|
---|
114 | }
|
---|
115 | public ILookupParameter<DoubleValue> MoveQualityParameter
|
---|
116 | {
|
---|
117 | get { return (ILookupParameter<DoubleValue>)Parameters[MoveQualityName]; }
|
---|
118 | }
|
---|
119 | public ILookupParameter<DoubleValue> LastAcceptedQualityParameter
|
---|
120 | {
|
---|
121 | get { return (ILookupParameter<DoubleValue>)Parameters[LastAcceptedQualityName]; }
|
---|
122 | }
|
---|
123 |
|
---|
124 | #endregion
|
---|
125 |
|
---|
126 | public AcceptanceRatioReheatingOperator() : base()
|
---|
127 | {
|
---|
128 | #region Create parameters
|
---|
129 | Parameters.Add(new LookupParameter<DoubleValue>(TemperatureName, "The current temperature."));
|
---|
130 | Parameters.Add(new LookupParameter<DoubleValue>(LowerTemperatureName, "The lower bound of the temperature."));
|
---|
131 | Parameters.Add(new LookupParameter<IntValue>(IterationsName, "The number of iterations."));
|
---|
132 | Parameters.Add(new LookupParameter<IDiscreteDoubleValueModifier>(AnnealingOperatorName, "The operator that cools the temperature."));
|
---|
133 | Parameters.Add(new LookupParameter<IntValue>(TemperatureStartIndexName, "The index where the annealing or heating was last changed."));
|
---|
134 | Parameters.Add(new LookupParameter<DoubleValue>(StartTemperatureName, "The temperature from which cooling or reheating should occur."));
|
---|
135 | Parameters.Add(new LookupParameter<DoubleValue>(EndTemperatureName, "The temperature to which should be cooled or heated."));
|
---|
136 | Parameters.Add(new LookupParameter<IntValue>(MaximumIterationsName, "The maximum number of iterations which should be processed."));
|
---|
137 | Parameters.Add(new LookupParameter<BoolValue>(IsAcceptedName, "Whether the move was accepted or not."));
|
---|
138 | Parameters.Add(new LookupParameter<ItemList<BoolValue>>(AcceptanceMemoryName, "Memorizes the last N acceptance decisions."));
|
---|
139 | Parameters.Add(new LookupParameter<BoolValue>(CoolingName, "True when the temperature should be cooled, false otherwise."));
|
---|
140 | Parameters.Add(new ValueLookupParameter<DoubleValue>(UpperTemperatureName, "The upper bound of the temperature.", "InitialTemperature"));
|
---|
141 | Parameters.Add(new ConstrainedValueParameter<IDiscreteDoubleValueModifier>(ReheatingOperatorName, "The operator that reheats the temperature."));
|
---|
142 | Parameters.Add(new ValueParameter<DoubleRange>(ThresholdName, "The threshold controls the temperature. 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.", new DoubleRange(0.01, 0.1)));
|
---|
143 | Parameters.Add(new ValueParameter<IntValue>(MemorySizeName, "The maximum size of the acceptance memory.", new IntValue(100)));
|
---|
144 | Parameters.Add(new LookupParameter<DoubleValue>(AverageAcceptanceRatioName, "Average acceptance over full acceptance memory."));
|
---|
145 | Parameters.Add(new ValueParameter<IntValue>(ReheatWindowSizeName, "The amount of iterations each reheat needs to heat the current temperature to upper temperature.", new IntValue(10000)));
|
---|
146 | Parameters.Add(new LookupParameter<DoubleValue>(LastAcceptedQualityName, "Quality of last accepted solution."));
|
---|
147 | Parameters.Add(new LookupParameter<DoubleValue>(MoveQualityName, "The value which represents the quality of a move."));
|
---|
148 | #endregion
|
---|
149 |
|
---|
150 | foreach (var op in ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>().OrderBy(x => x.Name))
|
---|
151 | {
|
---|
152 | ReheatingOperatorParameter.ValidValues.Add((IDiscreteDoubleValueModifier) op);
|
---|
153 | }
|
---|
154 | Parameterize();
|
---|
155 | }
|
---|
156 |
|
---|
157 | [StorableConstructor]
|
---|
158 | protected AcceptanceRatioReheatingOperator(bool deserializing) : base(deserializing) { }
|
---|
159 | protected AcceptanceRatioReheatingOperator(AcceptanceRatioReheatingOperator original, Cloner cloner) : base(original, cloner) { }
|
---|
160 |
|
---|
161 |
|
---|
162 | public override IDeepCloneable Clone(Cloner cloner)
|
---|
163 | {
|
---|
164 | return new AcceptanceRatioReheatingOperator(this, cloner);
|
---|
165 | }
|
---|
166 |
|
---|
167 | public void Parameterize()
|
---|
168 | {
|
---|
169 | foreach (var op in ReheatingOperatorParameter.ValidValues)
|
---|
170 | {
|
---|
171 | op.IndexParameter.ActualName = IterationsName;
|
---|
172 | op.IndexParameter.Hidden = true;
|
---|
173 | op.StartIndexParameter.Value = null;
|
---|
174 | op.StartIndexParameter.ActualName = TemperatureStartIndexName;
|
---|
175 | op.EndIndexParameter.ActualName = MaximumIterationsParameter.Name;
|
---|
176 | op.ValueParameter.ActualName = TemperatureName;
|
---|
177 | op.ValueParameter.Hidden = true;
|
---|
178 | op.StartValueParameter.ActualName = StartTemperatureName;
|
---|
179 | op.StartValueParameter.Hidden = true;
|
---|
180 | op.EndValueParameter.ActualName = EndTemperatureName;
|
---|
181 | op.EndValueParameter.Hidden = true;
|
---|
182 | }
|
---|
183 | }
|
---|
184 |
|
---|
185 | public override IOperation Apply()
|
---|
186 | {
|
---|
187 | var isAccepted = IsAcceptedParameter.ActualValue.Value && LastAcceptedQualityParameter.ActualValue.Value != MoveQualityParameter.ActualValue.Value;
|
---|
188 | var acceptances = AcceptanceMemoryParameter.ActualValue;
|
---|
189 | var cooling = CoolingParameter.ActualValue.Value;
|
---|
190 | var ratioAmount = AverageAcceptanceRatioParameter.ActualValue;
|
---|
191 |
|
---|
192 | acceptances.Add(new BoolValue(isAccepted));
|
---|
193 | ratioAmount.Value += isAccepted ? 1 : 0;
|
---|
194 |
|
---|
195 | if (acceptances.Count > MemorySizeParameter.Value.Value) {
|
---|
196 | ratioAmount.Value -= acceptances.ElementAt(0).Value ? 1 : 0;
|
---|
197 | acceptances.RemoveAt(0);
|
---|
198 | }
|
---|
199 |
|
---|
200 | // only reheat when at least MemorySizeParameter.Value iterations have passed
|
---|
201 | if (acceptances.Count == MemorySizeParameter.Value.Value)
|
---|
202 | {
|
---|
203 | var ratio = ratioAmount.Value / MemorySizeParameter.Value.Value;
|
---|
204 | var ratioStart = ThresholdParameter.Value.Start;
|
---|
205 | var ratioEnd = ThresholdParameter.Value.End;
|
---|
206 |
|
---|
207 | if (!cooling && ratio >= ratioEnd)
|
---|
208 | {
|
---|
209 | // if we are heating, but should be cooling
|
---|
210 | cooling = true;
|
---|
211 | TemperatureStartIndexParameter.ActualValue.Value = Math.Max(0, IterationsParameter.ActualValue.Value - 1);
|
---|
212 | StartTemperatureParameter.ActualValue.Value = TemperatureParameter.ActualValue.Value;
|
---|
213 | EndTemperatureParameter.ActualValue.Value = LowerTemperatureParameter.ActualValue.Value;
|
---|
214 | }
|
---|
215 | else if (cooling && ratio <= ratioStart)
|
---|
216 | {
|
---|
217 | // if we are cooling but should be heating
|
---|
218 | cooling = false;
|
---|
219 | TemperatureStartIndexParameter.ActualValue.Value = Math.Max(0, IterationsParameter.ActualValue.Value - 1);
|
---|
220 | StartTemperatureParameter.ActualValue.Value = TemperatureParameter.ActualValue.Value;
|
---|
221 | EndTemperatureParameter.ActualValue.Value = UpperTemperatureParameter.ActualValue.Value;
|
---|
222 | ReheatingOperatorParameter.Value.EndIndexParameter.Value = new IntValue(
|
---|
223 | Math.Min(MaximumIterationsParameter.ActualValue.Value, IterationsParameter.ActualValue.Value + ReheatWindowSizeParameter.Value.Value));
|
---|
224 | }
|
---|
225 |
|
---|
226 | CoolingParameter.ActualValue.Value = cooling;
|
---|
227 | }
|
---|
228 |
|
---|
229 | if (isAccepted)
|
---|
230 | {
|
---|
231 | LastAcceptedQualityParameter.ActualValue.Value = MoveQualityParameter.ActualValue.Value;
|
---|
232 | }
|
---|
233 |
|
---|
234 | return cooling ? Cool() : Heat();
|
---|
235 | }
|
---|
236 |
|
---|
237 | private IOperation Heat()
|
---|
238 | {
|
---|
239 | return new OperationCollection {
|
---|
240 | ExecutionContext.CreateOperation(ReheatingOperatorParameter.Value),
|
---|
241 | base.Apply()
|
---|
242 | };
|
---|
243 | }
|
---|
244 |
|
---|
245 | private IOperation Cool()
|
---|
246 | {
|
---|
247 | return new OperationCollection {
|
---|
248 | ExecutionContext.CreateOperation(AnnealingOperatorParameter.ActualValue),
|
---|
249 | base.Apply()
|
---|
250 | };
|
---|
251 | }
|
---|
252 | }
|
---|
253 | }
|
---|