Free cookie consent management tool by TermsFeed Policy Generator

source: branches/1772_HeuristicLab.EvolutionTracking/HeuristicLab.EvolutionTracking/3.4/Analyzers/GenealogyAnalyzer.cs @ 17434

Last change on this file since 17434 was 17434, checked in by bburlacu, 4 years ago

#1772: Merge trunk changes and fix all errors and compilation warnings.

File size: 15.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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 License Information
21
22using System.Collections.Generic;
23using System.Linq;
24using HEAL.Attic;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.EvolutionTracking;
29using HeuristicLab.Operators;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32
33[Item("GenealogyAnalyzer", "An analyzer which performs the necessary instrumentation to record the evolution of a genetic algorithm.")]
34[StorableType("04001C52-025C-4555-8812-AC3FA26A2B2F")]
35public abstract class GenealogyAnalyzer<T> : SingleSuccessorOperator, IAnalyzer
36where T : class, IItem
37{
38  #region parameter names
39  private const string GenerationsParameterName = "Generations";
40  private const string ResultsParameterName = "Results";
41  private const string PopulationGraphParameterName = "PopulationGraph";
42  public const string QualityParameterName = "Quality";
43  public const string PopulationParameterName = "SymbolicExpressionTree";
44
45  private const string CrossoverParameterName = "Crossover";
46  private const string ManipulatorParameterName = "Mutator";
47  private const string SolutionCreatorParameterName = "SolutionCreator";
48
49  private const string BeforeCrossoverOperatorParameterName = "BeforeCrossoverOperator";
50  private const string AfterCrossoverOperatorParameterName = "AfterCrossoverOperator";
51
52  private const string BeforeManipulatorOperatorParameterName = "BeforeManipulatorOperator";
53  private const string AfterManipulatorOperatorParameterName = "AfterManipulatorOperator";
54
55  private const string EnableCrossoverTrackingParameterName = "EnableCrossoverTracking";
56  private const string EnableManipulatorTrackingParameterName = "EnableManipulatorTracking";
57  private const string EnableSolutionCreatorTrackingParameterName = "EnableSolutionCreatorTracking"; // should always be enabled. maybe superfluous
58  private const string TrimOlderGenerationsParameterName = "TrimOlderGenerations";
59  #endregion parameter names
60
61  #region parameter properties
62
63  public IFixedValueParameter<BoolValue> TrimOlderGenerationsParameter {
64    get { return (IFixedValueParameter<BoolValue>)Parameters[TrimOlderGenerationsParameterName]; }
65  }
66
67  public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
68    get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
69  }
70
71  public IScopeTreeLookupParameter<T> PopulationParameter {
72    get { return (IScopeTreeLookupParameter<T>)Parameters[PopulationParameterName]; }
73  }
74
75  public IValueParameter<ICrossoverOperator<T>> BeforeCrossoverOperatorParameter {
76    get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[BeforeCrossoverOperatorParameterName]; }
77  }
78
79  public IValueParameter<ICrossoverOperator<T>> AfterCrossoverOperatorParameter {
80    get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[AfterCrossoverOperatorParameterName]; }
81  }
82
83  public IValueParameter<IManipulatorOperator<T>> BeforeManipulatorOperatorParameter {
84    get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[BeforeManipulatorOperatorParameterName]; }
85  }
86
87  public IValueParameter<IManipulatorOperator<T>> AfterManipulatorOperatorParameter {
88    get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[AfterManipulatorOperatorParameterName]; }
89  }
90
91  public ILookupParameter<ResultCollection> ResultsParameter {
92    get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
93  }
94
95  public ILookupParameter<IntValue> GenerationsParameter {
96    get { return (ILookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
97  }
98
99  public IValueParameter<BoolValue> EnableCrossoverTrackingParameter {
100    get { return (IValueParameter<BoolValue>)Parameters[EnableCrossoverTrackingParameterName]; }
101  }
102
103  public IValueParameter<BoolValue> EnableManipulatorTrackingParameter {
104    get { return (IValueParameter<BoolValue>)Parameters[EnableManipulatorTrackingParameterName]; }
105  }
106
107  public IValueParameter<BoolValue> EnableSolutionCreatorTrackingParameter {
108    get { return (IValueParameter<BoolValue>)Parameters[EnableSolutionCreatorTrackingParameterName]; }
109  }
110
111  public ILookupParameter<ICrossover> CrossoverParameter {
112    get { return (ILookupParameter<ICrossover>)Parameters[CrossoverParameterName]; }
113  }
114
115  public ILookupParameter<IManipulator> ManipulatorParameter {
116    get { return (ILookupParameter<IManipulator>)Parameters[ManipulatorParameterName]; }
117  }
118
119  public ILookupParameter<ISolutionCreator> SolutionCreatorParameter {
120    get { return (ILookupParameter<ISolutionCreator>)Parameters[SolutionCreatorParameterName]; }
121  }
122  #endregion parameter properties
123
124  #region properties
125  public ICrossoverOperator<T> BeforeCrossoverOperator {
126    get { return BeforeCrossoverOperatorParameter.Value; }
127  }
128
129  public ICrossoverOperator<T> AfterCrossoverOperator {
130    get { return AfterCrossoverOperatorParameter.Value; }
131  }
132
133  public IManipulatorOperator<T> BeforeManipulatorOperator {
134    get { return BeforeManipulatorOperatorParameter.Value; }
135  }
136
137  public IManipulatorOperator<T> AfterManipulatorOperator {
138    get { return AfterManipulatorOperatorParameter.Value; }
139  }
140
141  public BoolValue EnableCrossoverTracking {
142    get { return EnableCrossoverTrackingParameter.Value; }
143  }
144
145  public BoolValue EnableManipulatorTracking {
146    get { return EnableManipulatorTrackingParameter.Value; }
147  }
148
149  public BoolValue EnableSolutionCreatorTracking {
150    get { return EnableSolutionCreatorTrackingParameter.Value; }
151  }
152
153  public bool TrimOlderGenerations {
154    get { return TrimOlderGenerationsParameter.Value.Value; }
155  }
156  #endregion properties
157
158  protected GenealogyAnalyzer() {
159    #region add parameters
160    // the instrumented operators
161    Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
162    Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
163    Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
164    // the analyzer parameters
165    Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
166    Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
167    Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
168    // parameters required by the analyzer to do its work
169    Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
170    Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
171    Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
172    Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
173    Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(BeforeCrossoverOperatorParameterName));
174    Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(AfterCrossoverOperatorParameterName));
175    Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(BeforeManipulatorOperatorParameterName));
176    Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(AfterManipulatorOperatorParameterName));
177    Parameters.Add(new FixedValueParameter<BoolValue>(TrimOlderGenerationsParameterName, "Remove all the generations older than the last generation from the genealoy graph to save memory."));
178    #endregion add parameters
179  }
180
181  protected GenealogyAnalyzer(GenealogyAnalyzer<T> original, Cloner cloner)
182    : base(original, cloner) {
183  }
184
185  [StorableConstructor]
186  protected GenealogyAnalyzer(StorableConstructorFlag _) : base(_) { }
187
188  [StorableHook(HookType.AfterDeserialization)]
189  private void AfterDeserialization() {
190    // the instrumented operators
191    if (!Parameters.ContainsKey(CrossoverParameterName))
192      Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
193    if (!Parameters.ContainsKey(ManipulatorParameterName))
194      Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
195    if (!Parameters.ContainsKey(SolutionCreatorParameterName))
196      Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
197    // the analyzer parameters
198    if (!Parameters.ContainsKey(EnableCrossoverTrackingParameterName))
199      Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
200    if (!Parameters.ContainsKey(EnableManipulatorTrackingParameterName))
201      Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
202    if (!Parameters.ContainsKey(EnableSolutionCreatorTrackingParameterName))
203      Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
204    // parameters required by the analyzer to do its work
205    if (!Parameters.ContainsKey(GenerationsParameterName))
206      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
207    if (!Parameters.ContainsKey(ResultsParameterName))
208      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
209    if (!Parameters.ContainsKey(PopulationParameterName)) {
210      Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
211    }
212    if (!Parameters.ContainsKey(QualityParameterName)) {
213      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
214    }
215    if (!Parameters.ContainsKey(TrimOlderGenerationsParameterName))
216      Parameters.Add(new FixedValueParameter<BoolValue>(TrimOlderGenerationsParameterName, "Remove all the generations older than the last generation from the genealoy graph to save memory."));
217  }
218
219  public bool EnabledByDefault {
220    get { return false; }
221  }
222
223  private void ConfigureTrackingOperators() {
224    // at the beginning we add the before/after operators to the instrumented operators
225    var crossover = CrossoverParameter.ActualValue;
226    if (crossover != null) {
227      var instrumentedCrossover = (InstrumentedOperator)crossover;
228      instrumentedCrossover.AfterExecutionOperators.Clear();
229      instrumentedCrossover.BeforeExecutionOperators.Clear();
230
231      if (EnableCrossoverTracking.Value) {
232        if (BeforeCrossoverOperator != null) {
233          instrumentedCrossover.BeforeExecutionOperators.Add(BeforeCrossoverOperator);
234        }
235        if (AfterCrossoverOperator != null) {
236          instrumentedCrossover.AfterExecutionOperators.Add(AfterCrossoverOperator);
237        }
238      }
239    }
240    var manipulator = ManipulatorParameter.ActualValue;
241    if (manipulator != null) {
242      var instrumentedManipulator = (InstrumentedOperator)manipulator;
243      instrumentedManipulator.AfterExecutionOperators.Clear();
244      instrumentedManipulator.BeforeExecutionOperators.Clear();
245
246      if (EnableManipulatorTracking.Value) {
247        if (BeforeManipulatorOperator != null) {
248          instrumentedManipulator.BeforeExecutionOperators.Add(BeforeManipulatorOperator);
249        }
250        if (AfterManipulatorOperator != null) {
251          instrumentedManipulator.AfterExecutionOperators.Add(AfterManipulatorOperator);
252        }
253      }
254    }
255  }
256
257  protected abstract void EvaluateIntermediateChildren();
258
259  public override IOperation Apply() {
260    IGenealogyGraph<T> genealogyGraph;
261    var results = ResultsParameter.ActualValue;
262    if (!results.ContainsKey(PopulationGraphParameterName)) {
263      genealogyGraph = new GenealogyGraph<T>();
264      results.Add(new Result(PopulationGraphParameterName, genealogyGraph));
265    } else {
266      genealogyGraph = (IGenealogyGraph<T>)results[PopulationGraphParameterName].Value;
267    }
268
269    var population = PopulationParameter.ActualValue;
270    var qualities = QualityParameter.ActualValue;
271
272    int generation = GenerationsParameter.ActualValue.Value;
273    if (generation == 0) {
274      ConfigureTrackingOperators();
275
276      for (int i = 0; i < population.Length; ++i) {
277        var individual = population[i];
278        var vertex = new GenealogyGraphNode<T>(individual) { Rank = generation };
279        genealogyGraph.AddVertex(vertex);
280        // save the vertex id in the individual scope (so that we can identify graph indices)
281        ExecutionContext.Scope.SubScopes[i].Variables.Add(new Variable("Id", new StringValue(vertex.Id)));
282      }
283    } else {
284      int index = 0;
285      T elite = null;
286      // identify previous elite individual
287      for (int i = 0; i < population.Length; ++i) {
288        if (genealogyGraph.GetByContent(population[i]).Rank.Equals(generation - 1)) {
289          elite = population[i];
290          index = i;
291          break;
292        }
293      }
294      // add current elite and connect with previous
295      #region add elite in the graph and connect it with the previous elite
296      if (elite != null) {
297        var prevVertex = genealogyGraph.GetByContent(elite);
298        prevVertex.IsElite = true; // mark elites in the graph retroactively
299        var v = (IGenealogyGraphNode<T>)prevVertex.Clone();
300        v.Rank = generation;
301        v.IsElite = false;
302        population[index] = v.Data;
303        genealogyGraph.AddVertex(v);
304        genealogyGraph.AddArc(prevVertex, v);
305        // inject the graph node unique id to the scope
306        ExecutionContext.Scope.SubScopes[index].Variables[BeforeManipulatorOperator.ChildParameter.ActualName].Value = v.Data;
307        ExecutionContext.Scope.SubScopes[index].Variables["Id"].Value = new StringValue(v.Id);
308      }
309      #endregion add elite in the graph and connect it with the previous elite
310    }
311    // update qualities
312    for (int i = 0; i < population.Length; ++i) {
313      var vertex = genealogyGraph.GetByContent(population[i]);
314      vertex.Quality = qualities[i].Value;
315    }
316    // update qualities for intermediate vertices
317    EvaluateIntermediateChildren();
318
319    // remove extra graph nodes (added by the instrumented operators in the case of offspring selection)
320    var pop = new HashSet<T>(population);
321    var discarded = genealogyGraph.GetByRank(generation).Where(x => !pop.Contains(x.Data)).ToList();
322    for (int i = 0; i < discarded.Count; ++i) {
323      var v = discarded[i];
324      if (v.InDegree == 1) {
325        var p = v.Parents.First();
326        if (p.Rank.Equals(generation - 0.5))
327          // the individual was a product of mutation. since it wasn't selected, we must remove both it and its parent
328          // ("intermediate" vertex result of crossover)
329          discarded.Add(v.Parents.First());
330      }
331    }
332    genealogyGraph.RemoveVertices(discarded);
333
334    //trim
335    if (TrimOlderGenerations) {
336      var vertices = genealogyGraph.Vertices.Where(x => x.Rank < generation - 1).ToList(); // select all ranks older than the previous generation
337      genealogyGraph.RemoveVertices(vertices);
338    }
339
340    return base.Apply();
341  }
342}
Note: See TracBrowser for help on using the repository browser.