1 | #region License Information
|
---|
2 | /* HeuristicLab
|
---|
3 | * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
4 | *
|
---|
5 | * This file is part of HeuristicLab.
|
---|
6 | *
|
---|
7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
8 | * it under the terms of the GNU General Public License as published by
|
---|
9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
10 | * (at your option) any later version.
|
---|
11 | *
|
---|
12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | * GNU General Public License for more details.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License
|
---|
18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 | #endregion
|
---|
21 |
|
---|
22 | using System;
|
---|
23 | using System.Linq;
|
---|
24 | using HeuristicLab.Analysis;
|
---|
25 | using HeuristicLab.Common;
|
---|
26 | using HeuristicLab.Core;
|
---|
27 | using HeuristicLab.Data;
|
---|
28 | using HeuristicLab.Operators;
|
---|
29 | using HeuristicLab.Optimization;
|
---|
30 | using HeuristicLab.Optimization.Operators;
|
---|
31 | using HeuristicLab.Parameters;
|
---|
32 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
33 | using HeuristicLab.PluginInfrastructure;
|
---|
34 |
|
---|
35 | namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
|
---|
36 | [Item("EliteOffspringSelector", "M2")]
|
---|
37 | [StorableClass]
|
---|
38 | public class EliteOffspringSelector : InstrumentedOperator, IOffspringSelector {
|
---|
39 |
|
---|
40 | private const string SuccessRatioChart = "SuccessRatioChart";
|
---|
41 | private const string SuccessRatioDataRow = "SuccessRatio";
|
---|
42 |
|
---|
43 |
|
---|
44 | public ValueLookupParameter<DoubleValue> MaximumSelectionPressureParameter {
|
---|
45 | get { return (ValueLookupParameter<DoubleValue>)Parameters["MaximumSelectionPressure"]; }
|
---|
46 | }
|
---|
47 | public ValueLookupParameter<DoubleValue> SuccessRatioParameter {
|
---|
48 | get { return (ValueLookupParameter<DoubleValue>)Parameters["SuccessRatio"]; }
|
---|
49 | }
|
---|
50 | public LookupParameter<DoubleValue> SelectionPressureParameter {
|
---|
51 | get { return (ValueLookupParameter<DoubleValue>)Parameters["SelectionPressure"]; }
|
---|
52 | }
|
---|
53 | public LookupParameter<DoubleValue> CurrentSuccessRatioParameter {
|
---|
54 | get { return (LookupParameter<DoubleValue>)Parameters["CurrentSuccessRatio"]; }
|
---|
55 | }
|
---|
56 | public LookupParameter<ItemList<IScope>> OffspringPopulationParameter {
|
---|
57 | get { return (LookupParameter<ItemList<IScope>>)Parameters["OffspringPopulation"]; }
|
---|
58 | }
|
---|
59 | public LookupParameter<IntValue> OffspringPopulationWinnersParameter {
|
---|
60 | get { return (LookupParameter<IntValue>)Parameters["OffspringPopulationWinners"]; }
|
---|
61 | }
|
---|
62 | public ScopeTreeLookupParameter<BoolValue> SuccessfulOffspringParameter {
|
---|
63 | get { return (ScopeTreeLookupParameter<BoolValue>)Parameters["SuccessfulOffspring"]; }
|
---|
64 | }
|
---|
65 | public IValueLookupParameter<BoolValue> FillPopulationWithParentsParameter {
|
---|
66 | get { return (IValueLookupParameter<BoolValue>)Parameters["FillPopulationWithParents"]; }
|
---|
67 | }
|
---|
68 | public ILookupParameter<BoolValue> EnoughChildrenGeneratedParameter {
|
---|
69 | get { return (ILookupParameter<BoolValue>)Parameters["EnoughChildrenGenerated"]; }
|
---|
70 | }
|
---|
71 | public IValueLookupParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
|
---|
72 | get { return (IValueLookupParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
|
---|
73 | }
|
---|
74 | public ValueLookupParameter<ResultCollection> ResultsParameter {
|
---|
75 | get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
|
---|
76 | }
|
---|
77 |
|
---|
78 | public ValueLookupParameter<DoubleValue> DiversityComparisonFactorParameter {
|
---|
79 | get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactor"]; }
|
---|
80 | }
|
---|
81 | private ValueLookupParameter<DoubleValue> ComparisonFactorLowerBoundParameter {
|
---|
82 | get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactorLowerBound"]; }
|
---|
83 | }
|
---|
84 | private ValueLookupParameter<DoubleValue> ComparisonFactorUpperBoundParameter {
|
---|
85 | get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactorUpperBound"]; }
|
---|
86 | }
|
---|
87 |
|
---|
88 | public IConstrainedValueParameter<IDiscreteDoubleValueModifier> ComparisonFactorModifierParameter {
|
---|
89 | get { return (IConstrainedValueParameter<IDiscreteDoubleValueModifier>)Parameters["ComparisonFactorModifier"]; }
|
---|
90 | }
|
---|
91 |
|
---|
92 | [StorableConstructor]
|
---|
93 | protected EliteOffspringSelector(bool deserializing) : base(deserializing) { }
|
---|
94 | protected EliteOffspringSelector(EliteOffspringSelector original, Cloner cloner)
|
---|
95 | : base(original, cloner) {
|
---|
96 | }
|
---|
97 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
98 | return new EliteOffspringSelector(this, cloner);
|
---|
99 | }
|
---|
100 | public EliteOffspringSelector()
|
---|
101 | : base() {
|
---|
102 | Parameters.Add(new ValueLookupParameter<DoubleValue>("MaximumSelectionPressure", "The maximum selection pressure which prematurely terminates the offspring selection step."));
|
---|
103 | Parameters.Add(new ValueLookupParameter<DoubleValue>("SuccessRatio", "The ratio of successful offspring that has to be produced."));
|
---|
104 | Parameters.Add(new ValueLookupParameter<DoubleValue>("SelectionPressure", "The amount of selection pressure currently necessary to fulfill the success ratio."));
|
---|
105 | Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentSuccessRatio", "The current success ratio indicates how much of the successful offspring have already been generated."));
|
---|
106 | Parameters.Add(new LookupParameter<ItemList<IScope>>("OffspringPopulation", "Temporary store of the offspring population."));
|
---|
107 | Parameters.Add(new LookupParameter<IntValue>("OffspringPopulationWinners", "Temporary store the number of successful offspring in the offspring population."));
|
---|
108 | Parameters.Add(new ScopeTreeLookupParameter<BoolValue>("SuccessfulOffspring", "True if the offspring was more successful than its parents.", 2));
|
---|
109 | Parameters.Add(new ValueLookupParameter<BoolValue>("FillPopulationWithParents", "True if the population should be filled with parent individual or false if worse children should be used when the maximum selection pressure is exceeded."));
|
---|
110 | Parameters.Add(new LookupParameter<BoolValue>("EnoughChildrenGenerated", "True if enough children have been generated, otherwise false."));
|
---|
111 | Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
|
---|
112 | Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the population diversity analysis results should be stored."));
|
---|
113 |
|
---|
114 | Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them.", new DoubleValue(0.0)));
|
---|
115 | Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactorLowerBound", "The lower bound of the comparison factor (start).", new DoubleValue(0.5)));
|
---|
116 | Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactorUpperBound", "The upper bound of the comparison factor (end).", new DoubleValue(1.0)));
|
---|
117 | Parameters.Add(new OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>("ComparisonFactorModifier", "The operator used to modify the comparison factor.", new ItemSet<IDiscreteDoubleValueModifier>(new IDiscreteDoubleValueModifier[] { new LinearDiscreteDoubleValueModifier() }), new LinearDiscreteDoubleValueModifier()));
|
---|
118 |
|
---|
119 |
|
---|
120 | foreach (IDiscreteDoubleValueModifier modifier in ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>().OrderBy(x => x.Name))
|
---|
121 | ComparisonFactorModifierParameter.ValidValues.Add(modifier);
|
---|
122 | IDiscreteDoubleValueModifier linearModifier = ComparisonFactorModifierParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("LinearDiscreteDoubleValueModifier"));
|
---|
123 | if (linearModifier != null) ComparisonFactorModifierParameter.Value = linearModifier;
|
---|
124 | ParameterizeComparisonFactorModifiers();
|
---|
125 |
|
---|
126 | this.AfterExecutionOperators.Clear();
|
---|
127 | this.AfterExecutionOperators.Add(ComparisonFactorModifierParameter.Value);
|
---|
128 | ComparisonFactorModifierParameter.ValueChanged += ComparisonFactorModifierParameter_ValueChanged;
|
---|
129 | }
|
---|
130 |
|
---|
131 | void ComparisonFactorModifierParameter_ValueChanged(object sender, EventArgs e) {
|
---|
132 | this.AfterExecutionOperators.Clear();
|
---|
133 | this.AfterExecutionOperators.Add(ComparisonFactorModifierParameter.Value);
|
---|
134 | }
|
---|
135 |
|
---|
136 | private void ParameterizeComparisonFactorModifiers() {
|
---|
137 | //TODO: does not work if Generations parameter names are changed
|
---|
138 | foreach (IDiscreteDoubleValueModifier modifier in ComparisonFactorModifierParameter.ValidValues) {
|
---|
139 | modifier.IndexParameter.ActualName = "Generations";
|
---|
140 | modifier.EndIndexParameter.ActualName = "MaximumGenerations";
|
---|
141 | modifier.EndValueParameter.ActualName = ComparisonFactorUpperBoundParameter.Name;
|
---|
142 | modifier.StartIndexParameter.Value = new IntValue(0);
|
---|
143 | modifier.StartValueParameter.ActualName = ComparisonFactorLowerBoundParameter.Name;
|
---|
144 | modifier.ValueParameter.ActualName = "DiversityComparisonFactor";
|
---|
145 | }
|
---|
146 | }
|
---|
147 |
|
---|
148 | public override IOperation InstrumentedApply() {
|
---|
149 | double maxSelPress = MaximumSelectionPressureParameter.ActualValue.Value;
|
---|
150 | double successRatio = SuccessRatioParameter.ActualValue.Value;
|
---|
151 | bool fillPopulationWithParents = false;
|
---|
152 | if (FillPopulationWithParentsParameter.ActualValue != null)
|
---|
153 | fillPopulationWithParents = FillPopulationWithParentsParameter.ActualValue.Value;
|
---|
154 | IScope scope = ExecutionContext.Scope;
|
---|
155 | IScope parents = scope.SubScopes[0];
|
---|
156 | IScope offspring = scope.SubScopes[1];
|
---|
157 | int populationSize = parents.SubScopes.Count;
|
---|
158 |
|
---|
159 | // retrieve actual selection pressure and success ratio
|
---|
160 | DoubleValue selectionPressure = SelectionPressureParameter.ActualValue;
|
---|
161 | if (selectionPressure == null) {
|
---|
162 | selectionPressure = new DoubleValue(0);
|
---|
163 | SelectionPressureParameter.ActualValue = selectionPressure;
|
---|
164 | }
|
---|
165 | DoubleValue currentSuccessRatio = CurrentSuccessRatioParameter.ActualValue;
|
---|
166 | if (currentSuccessRatio == null) {
|
---|
167 | currentSuccessRatio = new DoubleValue(0);
|
---|
168 | CurrentSuccessRatioParameter.ActualValue = currentSuccessRatio;
|
---|
169 | }
|
---|
170 |
|
---|
171 | DataTable successRatioDataTable;
|
---|
172 | if (ResultsParameter.ActualValue.ContainsKey(SuccessRatioChart)) {
|
---|
173 | successRatioDataTable = (DataTable)ResultsParameter.ActualValue[SuccessRatioChart].Value;
|
---|
174 | } else {
|
---|
175 | successRatioDataTable = new DataTable(SuccessRatioChart);
|
---|
176 | successRatioDataTable.Rows.Add(new DataRow(SuccessRatioDataRow));
|
---|
177 | ResultsParameter.ActualValue.Add(new Result(SuccessRatioChart, successRatioDataTable));
|
---|
178 | }
|
---|
179 |
|
---|
180 | // retrieve next population
|
---|
181 | ItemList<IScope> population = OffspringPopulationParameter.ActualValue;
|
---|
182 | IntValue successfulOffspring;
|
---|
183 | if (population == null) {
|
---|
184 | population = new ItemList<IScope>();
|
---|
185 | OffspringPopulationParameter.ActualValue = population;
|
---|
186 | selectionPressure.Value = 0; // initialize selection pressure for this round
|
---|
187 | currentSuccessRatio.Value = 0; // initialize current success ratio for this round
|
---|
188 | successfulOffspring = new IntValue(0);
|
---|
189 | OffspringPopulationWinnersParameter.ActualValue = successfulOffspring;
|
---|
190 | } else successfulOffspring = OffspringPopulationWinnersParameter.ActualValue;
|
---|
191 |
|
---|
192 | int worseOffspringNeeded = (int)((1 - successRatio) * populationSize) - (population.Count - successfulOffspring.Value);
|
---|
193 | int successfulOffspringAdded = 0;
|
---|
194 | double avgPopDiv = DiversityComparisonFactorParameter.Value.Value;
|
---|
195 |
|
---|
196 | // implement the ActualValue fetch here - otherwise the parent scope would also be included, given that there may be 1000 or more parents, this is quite unnecessary
|
---|
197 | string tname = SuccessfulOffspringParameter.TranslatedName;
|
---|
198 | double tmpSelPress = selectionPressure.Value, tmpSelPressInc = 1.0 / populationSize;
|
---|
199 | for (int i = 0; i < offspring.SubScopes.Count; i++) {
|
---|
200 | // fetch value
|
---|
201 | IVariable tmpVar;
|
---|
202 | if (!offspring.SubScopes[i].Variables.TryGetValue(tname, out tmpVar)) throw new InvalidOperationException(Name + ": Could not determine if an offspring was successful or not.");
|
---|
203 | BoolValue tmp = (tmpVar.Value as BoolValue);
|
---|
204 | if (tmp == null) throw new InvalidOperationException(Name + ": The variable that indicates whether an offspring is successful or not must contain a BoolValue.");
|
---|
205 |
|
---|
206 | if (!offspring.SubScopes[i].Variables.TryGetValue("ResultImprovement", out tmpVar)) throw new InvalidOperationException(Name + ": Could not find ResultImprovment.");
|
---|
207 | BoolValue betterThanWorseParent = (tmpVar.Value as BoolValue);
|
---|
208 | if (betterThanWorseParent == null) throw new InvalidOperationException(Name + ": Could not find ResultImprovment.");
|
---|
209 |
|
---|
210 | //this is an "elite" solution candidate
|
---|
211 | double tmpCurSuccRatio = (successfulOffspring.Value + successfulOffspringAdded) / (double)populationSize;
|
---|
212 | if (tmp.Value && tmpCurSuccRatio <= successRatio) {
|
---|
213 | //this overrides the diversity mechanism; always fill up elites if there is space
|
---|
214 | IScope currentOffspring = offspring.SubScopes[i];
|
---|
215 | offspring.SubScopes.Remove(currentOffspring);
|
---|
216 | i--;
|
---|
217 | population.Add(currentOffspring);
|
---|
218 | successfulOffspringAdded++;
|
---|
219 | } else if (!tmp.Value && betterThanWorseParent.Value) {
|
---|
220 | //quality is ok, check for diversity
|
---|
221 | IScope currentOffspring = offspring.SubScopes[i];
|
---|
222 |
|
---|
223 | if (!population.Any()) {
|
---|
224 | offspring.SubScopes.Remove(currentOffspring);
|
---|
225 | i--;
|
---|
226 | worseOffspringNeeded--;
|
---|
227 | population.Add(currentOffspring);
|
---|
228 | } else {
|
---|
229 | Scope tmpScope = new Scope();
|
---|
230 | tmpScope.SubScopes.AddRange(population);
|
---|
231 | Scope tmpCurrentScope = new Scope();
|
---|
232 | tmpCurrentScope.SubScopes.Add(currentOffspring);
|
---|
233 | double curDiv = SimilarityCalculatorParameter.ActualValue.CalculateSolutionCrowdSimilarity(tmpCurrentScope, tmpScope)[0].Average();
|
---|
234 | if (curDiv < avgPopDiv) {
|
---|
235 | if (worseOffspringNeeded > 0 || tmpSelPress >= maxSelPress) {
|
---|
236 | if (!fillPopulationWithParents || worseOffspringNeeded > 0) {
|
---|
237 | offspring.SubScopes.Remove(currentOffspring);
|
---|
238 | i--;
|
---|
239 | worseOffspringNeeded--;
|
---|
240 | } else {
|
---|
241 | currentOffspring = parents.SubScopes[i];
|
---|
242 | }
|
---|
243 | population.Add(currentOffspring);
|
---|
244 | }
|
---|
245 | }
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 | tmpSelPress += tmpSelPressInc;
|
---|
250 | if (population.Count >= populationSize) break;
|
---|
251 | }
|
---|
252 | successfulOffspring.Value += successfulOffspringAdded;
|
---|
253 |
|
---|
254 | // calculate actual selection pressure and success ratio
|
---|
255 | selectionPressure.Value = tmpSelPress;
|
---|
256 | currentSuccessRatio.Value = successfulOffspring.Value / ((double)populationSize);
|
---|
257 | successRatioDataTable.Rows[SuccessRatioDataRow].Values.Add(currentSuccessRatio.Value);
|
---|
258 |
|
---|
259 | if (EnoughChildrenGeneratedParameter.ActualValue == null) {
|
---|
260 | EnoughChildrenGeneratedParameter.ActualValue = new BoolValue();
|
---|
261 | }
|
---|
262 | // check if enough children have been generated
|
---|
263 | if (((selectionPressure.Value < maxSelPress) &&
|
---|
264 | (currentSuccessRatio.Value < successRatio) &&
|
---|
265 | (population.Count < populationSize)) ||
|
---|
266 | (population.Count < populationSize)) {
|
---|
267 | // more children required -> reduce left and start children generation again
|
---|
268 | scope.SubScopes.Remove(parents);
|
---|
269 | scope.SubScopes.Remove(offspring);
|
---|
270 | while (parents.SubScopes.Count > 0) {
|
---|
271 | IScope parent = parents.SubScopes[0];
|
---|
272 | parents.SubScopes.RemoveAt(0);
|
---|
273 | scope.SubScopes.Add(parent);
|
---|
274 | }
|
---|
275 | EnoughChildrenGeneratedParameter.ActualValue.Value = false;
|
---|
276 | } else {
|
---|
277 | // enough children generated
|
---|
278 | offspring.SubScopes.Clear();
|
---|
279 | offspring.SubScopes.AddRange(population);
|
---|
280 |
|
---|
281 | scope.Variables.Remove(OffspringPopulationParameter.TranslatedName);
|
---|
282 | scope.Variables.Remove(OffspringPopulationWinnersParameter.TranslatedName);
|
---|
283 | EnoughChildrenGeneratedParameter.ActualValue.Value = true;
|
---|
284 | }
|
---|
285 |
|
---|
286 | return base.InstrumentedApply();
|
---|
287 | }
|
---|
288 | }
|
---|
289 | }
|
---|