source: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/OffspringSelectors/PopDivOffspringSelector.cs @ 12352

Last change on this file since 12352 was 12352, checked in by ascheibe, 5 years ago

#2267 improved offspring selector

File size: 16.3 KB
Line 
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
22using System;
23using System.Linq;
24using HeuristicLab.Analysis;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Operators;
29using HeuristicLab.Optimization;
30using HeuristicLab.Optimization.Operators;
31using HeuristicLab.Parameters;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33using HeuristicLab.PluginInfrastructure;
34
35namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
36  [Item("PopDivOffspringSelector", "")]
37  [StorableClass]
38  public class PopDivOffspringSelector : 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 PopDivOffspringSelector(bool deserializing) : base(deserializing) { }
94    protected PopDivOffspringSelector(PopDivOffspringSelector original, Cloner cloner)
95      : base(original, cloner) {
96    }
97    public override IDeepCloneable Clone(Cloner cloner) {
98      return new PopDivOffspringSelector(this, cloner);
99    }
100    public PopDivOffspringSelector()
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
195      double avgPopDiv = DiversityComparisonFactorParameter.Value.Value;
196      bool takeWorseOffspring = false;
197
198      // 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
199      string tname = SuccessfulOffspringParameter.TranslatedName;
200      double tmpSelPress = selectionPressure.Value, tmpSelPressInc = 1.0 / populationSize;
201      int cnt = 0;
202      int stepWidth = offspring.SubScopes.Count / 5;
203      for (int i = 0; i < offspring.SubScopes.Count; i++) {
204        //calculate population diversity so far
205        if (cnt != 0 && cnt % stepWidth == 0) {
206          Scope tmpScope = new Scope();
207          tmpScope.SubScopes.AddRange(population);
208          double popDiversity = SimilarityCalculatorParameter.ActualValue.CalculateSolutionCrowdSimilarity(tmpScope).Average(x => x.Average());
209          //this assumes that low-quality solutions are of high diversity
210          if (popDiversity > avgPopDiv) {
211            takeWorseOffspring = true;
212          } else {
213            takeWorseOffspring = false;
214          }
215        }
216        cnt++;
217
218        // fetch value
219        IVariable tmpVar;
220        if (!offspring.SubScopes[i].Variables.TryGetValue(tname, out tmpVar)) throw new InvalidOperationException(Name + ": Could not determine if an offspring was successful or not.");
221        BoolValue tmp = (tmpVar.Value as BoolValue);
222        if (tmp == null) throw new InvalidOperationException(Name + ": The variable that indicates whether an offspring is successful or not must contain a BoolValue.");
223
224        if (takeWorseOffspring) {
225          IScope currentOffspring = offspring.SubScopes[i];
226          Scope tmpScope = new Scope();
227          tmpScope.SubScopes.AddRange(population);
228          Scope tmpCurrentScope = new Scope();
229          tmpCurrentScope.SubScopes.Add(currentOffspring);
230          double curDiv = SimilarityCalculatorParameter.ActualValue.CalculateSolutionCrowdSimilarity(tmpCurrentScope, tmpScope)[0].Average();
231          if (curDiv < avgPopDiv) {
232            offspring.SubScopes.Remove(currentOffspring);
233            i--;
234            population.Add(currentOffspring);
235            worseOffspringNeeded--;
236          }
237        } else if (tmp.Value) {
238          IScope currentOffspring = offspring.SubScopes[i];
239          offspring.SubScopes.Remove(currentOffspring);
240          i--;
241          population.Add(currentOffspring);
242          successfulOffspringAdded++;
243        } else if (worseOffspringNeeded > 0 || tmpSelPress >= maxSelPress) {
244          IScope currentOffspring;
245          if (!fillPopulationWithParents || worseOffspringNeeded > 0) {
246            currentOffspring = offspring.SubScopes[i];
247            offspring.SubScopes.Remove(currentOffspring);
248            i--;
249            worseOffspringNeeded--;
250          } else {
251            currentOffspring = parents.SubScopes[i];
252          }
253          population.Add(currentOffspring);
254        }
255        tmpSelPress += tmpSelPressInc;
256        if (population.Count >= populationSize) break;
257      }
258      successfulOffspring.Value += successfulOffspringAdded;
259
260      // calculate actual selection pressure and success ratio
261      selectionPressure.Value = tmpSelPress;
262      currentSuccessRatio.Value = successfulOffspring.Value / ((double)populationSize);
263      successRatioDataTable.Rows[SuccessRatioDataRow].Values.Add(currentSuccessRatio.Value);
264
265      if (EnoughChildrenGeneratedParameter.ActualValue == null) {
266        EnoughChildrenGeneratedParameter.ActualValue = new BoolValue();
267      }
268      // check if enough children have been generated
269      if (((selectionPressure.Value < maxSelPress) &&
270        (currentSuccessRatio.Value < successRatio) &&
271        (population.Count < populationSize)) ||
272          (population.Count < populationSize)) {
273        // more children required -> reduce left and start children generation again
274        scope.SubScopes.Remove(parents);
275        scope.SubScopes.Remove(offspring);
276        while (parents.SubScopes.Count > 0) {
277          IScope parent = parents.SubScopes[0];
278          parents.SubScopes.RemoveAt(0);
279          scope.SubScopes.Add(parent);
280        }
281        EnoughChildrenGeneratedParameter.ActualValue.Value = false;
282      } else {
283        // enough children generated
284        offspring.SubScopes.Clear();
285        offspring.SubScopes.AddRange(population);
286
287        scope.Variables.Remove(OffspringPopulationParameter.TranslatedName);
288        scope.Variables.Remove(OffspringPopulationWinnersParameter.TranslatedName);
289        EnoughChildrenGeneratedParameter.ActualValue.Value = true;
290      }
291
292      return base.InstrumentedApply();
293    }
294  }
295}
Note: See TracBrowser for help on using the repository browser.