Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.EvolutionTracking/3.4/Analyzers/GenealogyAnalyzer.cs @ 11032

Last change on this file since 11032 was 11032, checked in by bburlacu, 10 years ago

#1772: Minor change to the GenealogyAnalyzer (remove properties for retrieving LookupParameter values).

File size: 14.7 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.Linq;
23using HeuristicLab.Common;
24using HeuristicLab.Core;
25using HeuristicLab.Data;
26using HeuristicLab.Operators;
27using HeuristicLab.Optimization;
28using HeuristicLab.Parameters;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.EvolutionTracking {
32  [StorableClass]
33  [Item("GenealogyAnalyzer", "An analyzer which performs the necessary instrumentation to record the evolution of a genetic algorithm.")]
34  public class GenealogyAnalyzer<T> : SingleSuccessorOperator, IAnalyzer
35  where T : class,IItem {
36    private const string GenerationsParameterName = "Generations";
37    private const string ResultsParameterName = "Results";
38    private const string PopulationGraphParameterName = "PopulationGraph";
39    public const string QualityParameterName = "Quality";
40    public const string PopulationParameterName = "SymbolicExpressionTree";
41
42    private const string CrossoverParameterName = "Crossover";
43    private const string ManipulatorParameterName = "Mutator";
44    private const string SolutionCreatorParameterName = "SolutionCreator";
45
46    private const string BeforeCrossoverOperatorParameterName = "BeforeCrossoverOperator";
47    private const string AfterCrossoverOperatorParameterName = "AfterCrossoverOperator";
48
49    private const string BeforeManipulatorOperatorParameterName = "BeforeManipulatorOperator";
50    private const string AfterManipulatorOperatorParameterName = "AfterManipulatorOperator";
51
52    private const string EnableCrossoverTrackingParameterName = "EnableCrossoverTracking";
53    private const string EnableManipulatorTrackingParameterName = "EnableManipulatorTracking";
54    private const string EnableSolutionCreatorTrackingParameterName = "EnableSolutionCreatorTracking"; // should always be enabled. maybe superfluous
55
56    #region parameter properties
57    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
58      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
59    }
60    public IScopeTreeLookupParameter<T> PopulationParameter {
61      get { return (IScopeTreeLookupParameter<T>)Parameters[PopulationParameterName]; }
62    }
63    public IValueParameter<ICrossoverOperator<T>> BeforeCrossoverOperatorParameter {
64      get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[BeforeCrossoverOperatorParameterName]; }
65    }
66    public IValueParameter<ICrossoverOperator<T>> AfterCrossoverOperatorParameter {
67      get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[AfterCrossoverOperatorParameterName]; }
68    }
69    public IValueParameter<IManipulatorOperator<T>> BeforeManipulatorOperatorParameter {
70      get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[BeforeManipulatorOperatorParameterName]; }
71    }
72    public IValueParameter<IManipulatorOperator<T>> AfterManipulatorOperatorParameter {
73      get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[AfterManipulatorOperatorParameterName]; }
74    }
75    public ILookupParameter<ResultCollection> ResultsParameter {
76      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
77    }
78    public ILookupParameter<IntValue> GenerationsParameter {
79      get { return (ILookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
80    }
81    public IValueParameter<BoolValue> EnableCrossoverTrackingParameter {
82      get { return (IValueParameter<BoolValue>)Parameters[EnableCrossoverTrackingParameterName]; }
83    }
84    public IValueParameter<BoolValue> EnableManipulatorTrackingParameter {
85      get { return (IValueParameter<BoolValue>)Parameters[EnableManipulatorTrackingParameterName]; }
86    }
87    public IValueParameter<BoolValue> EnableSolutionCreatorTrackingParameter {
88      get { return (IValueParameter<BoolValue>)Parameters[EnableSolutionCreatorTrackingParameterName]; }
89    }
90    public ILookupParameter<ICrossover> CrossoverParameter {
91      get { return (ILookupParameter<ICrossover>)Parameters[CrossoverParameterName]; }
92    }
93    public ILookupParameter<IManipulator> ManipulatorParameter {
94      get { return (ILookupParameter<IManipulator>)Parameters[ManipulatorParameterName]; }
95    }
96
97    public ILookupParameter<ISolutionCreator> SolutionCreatorParameter {
98      get { return (ILookupParameter<ISolutionCreator>)Parameters[SolutionCreatorParameterName]; }
99    }
100    #endregion
101
102    #region properties
103    public ICrossoverOperator<T> BeforeCrossoverOperator {
104      get { return BeforeCrossoverOperatorParameter.Value; }
105    }
106    public ICrossoverOperator<T> AfterCrossoverOperator {
107      get { return AfterCrossoverOperatorParameter.Value; }
108    }
109    public IManipulatorOperator<T> BeforeManipulatorOperator {
110      get { return BeforeManipulatorOperatorParameter.Value; }
111    }
112    public IManipulatorOperator<T> AfterManipulatorOperator {
113      get { return AfterManipulatorOperatorParameter.Value; }
114    }
115    public BoolValue EnableCrossoverTracking {
116      get { return EnableCrossoverTrackingParameter.Value; }
117    }
118    public BoolValue EnableManipulatorTracking {
119      get { return EnableManipulatorTrackingParameter.Value; }
120    }
121    public BoolValue EnableSolutionCreatorTracking {
122      get { return EnableSolutionCreatorTrackingParameter.Value; }
123    }
124
125    public IGenealogyGraph<T> GenealogyGraph {
126      get {
127        IResult result;
128        var results = ResultsParameter.ActualValue;
129        if (!results.ContainsKey(PopulationGraphParameterName)) {
130          result = new Result(PopulationGraphParameterName, new GenealogyGraph<T>());
131          results.Add(result);
132        } else {
133          result = results[PopulationGraphParameterName];
134        }
135        var graph = (IGenealogyGraph<T>)result.Value;
136        return graph;
137      }
138    }
139    #endregion
140
141    public GenealogyAnalyzer() {
142      // the instrumented operators
143      Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
144      Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
145      Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
146      // the analyzer parameters
147      Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
148      Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
149      Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
150      // parameters required by the analyzer to do its work
151      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
152      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
153      Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
154      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
155      Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(BeforeCrossoverOperatorParameterName));
156      Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(AfterCrossoverOperatorParameterName));
157      Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(BeforeManipulatorOperatorParameterName));
158      Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(AfterManipulatorOperatorParameterName));
159    }
160    public override IDeepCloneable Clone(Cloner cloner) {
161      return new GenealogyAnalyzer<T>(this, cloner);
162    }
163    protected GenealogyAnalyzer(GenealogyAnalyzer<T> original, Cloner cloner)
164      : base(original, cloner) {
165    }
166    [StorableHook(HookType.AfterDeserialization)]
167    private void AfterDeserialization() {
168      // the instrumented operators
169      if (!Parameters.ContainsKey(CrossoverParameterName))
170        Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
171      if (!Parameters.ContainsKey(ManipulatorParameterName))
172        Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
173      if (!Parameters.ContainsKey(SolutionCreatorParameterName))
174        Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
175      // the analyzer parameters
176      if (!Parameters.ContainsKey(EnableCrossoverTrackingParameterName))
177        Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
178      if (!Parameters.ContainsKey(EnableManipulatorTrackingParameterName))
179        Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
180      if (!Parameters.ContainsKey(EnableSolutionCreatorTrackingParameterName))
181        Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
182      // parameters required by the analyzer to do its work
183      if (!Parameters.ContainsKey(GenerationsParameterName))
184        Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
185      if (!Parameters.ContainsKey(ResultsParameterName))
186        Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
187      if (!Parameters.ContainsKey(PopulationParameterName)) {
188        Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
189      }
190      if (!Parameters.ContainsKey(QualityParameterName)) {
191        Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
192      }
193    }
194
195    public bool EnabledByDefault {
196      get { return false; }
197    }
198
199    private void ConfigureTrackingOperators() {
200      // at the beginning we add the before/after operators to the instrumented operators
201      var crossover = CrossoverParameter.ActualValue;
202      if (crossover != null) {
203        var instrumentedCrossover = (InstrumentedOperator)crossover;
204        instrumentedCrossover.AfterExecutionOperators.Clear();
205        instrumentedCrossover.BeforeExecutionOperators.Clear();
206
207        if (EnableCrossoverTracking.Value) {
208          if (BeforeCrossoverOperator != null) {
209            instrumentedCrossover.BeforeExecutionOperators.Add(BeforeCrossoverOperator);
210          }
211          if (AfterCrossoverOperator != null) {
212            instrumentedCrossover.AfterExecutionOperators.Add(AfterCrossoverOperator);
213          }
214        }
215      }
216      var manipulator = ManipulatorParameter.ActualValue;
217      if (manipulator != null) {
218        var instrumentedManipulator = (InstrumentedOperator)manipulator;
219        instrumentedManipulator.AfterExecutionOperators.Clear();
220        instrumentedManipulator.BeforeExecutionOperators.Clear();
221
222        if (EnableManipulatorTracking.Value) {
223          if (BeforeManipulatorOperator != null) {
224            instrumentedManipulator.BeforeExecutionOperators.Add(BeforeManipulatorOperator);
225          }
226          if (AfterManipulatorOperator != null) {
227            instrumentedManipulator.AfterExecutionOperators.Add(AfterManipulatorOperator);
228          }
229        }
230      }
231    }
232
233    public override IOperation Apply() {
234      var population = PopulationParameter.ActualValue.ToList();
235      var qualities = QualityParameter.ActualValue.ToList();
236
237      int currentGeneration = GenerationsParameter.ActualValue.Value;
238      if (currentGeneration == 0) {
239        ConfigureTrackingOperators();
240
241        for (int i = 0; i < population.Count; ++i) {
242          var individual = population[i];
243          var vertex = new GenealogyGraphNode<T>(individual) { Rank = currentGeneration };
244          GenealogyGraph.AddVertex(vertex);
245          // save the vertex id in the individual scope (so that we can identify graph indices)
246          ExecutionContext.Scope.SubScopes[i].Variables.Add(new Variable("Id", new StringValue(vertex.Id)));
247        }
248      } else {
249        int index = 0;
250        T elite = null;
251        for (int i = 0; i < population.Count; ++i) {
252          if (GenealogyGraph.Contains(population[i])) {
253            elite = population[i];
254            index = i;
255          }
256          break;
257        }
258
259        if (elite != null) {
260          var prevVertex = (IGenealogyGraphNode<T>)GenealogyGraph.GetVertex(elite);
261          prevVertex.IsElite = true; // mark elites in the graph retroactively
262
263          var clone = (T)elite.Clone();
264
265          var vertex = new GenealogyGraphNode<T>(prevVertex.Content) {
266            Rank = currentGeneration,
267            Quality = prevVertex.Quality,
268            IsElite = false
269          };
270
271          prevVertex.Content = clone;
272          // inject the graph node unique id to the scope
273          ExecutionContext.Scope.SubScopes[index].Variables["Id"].Value = new StringValue(vertex.Id);
274
275          GenealogyGraph.AddVertex(vertex);
276
277          GenealogyGraph.AddArc(prevVertex, vertex); // connect current elite with previous elite
278
279          if (prevVertex.InArcs.Any()) {
280            vertex.InArcs.Last().Data = prevVertex.InArcs.Last().Data; // save the fragment in case there is one
281          }
282        }
283      }
284      // update qualities
285      for (int i = 0; i < population.Count; ++i) {
286        var vertex = (IGenealogyGraphNode)GenealogyGraph.GetVertex(population[i]);
287        vertex.Quality = qualities[i].Value;
288      }
289
290      // remove extra graph nodes (added by the instrumented operators in the case of offspring selection)
291      var discardedOffspring = GenealogyGraph.Ranks[currentGeneration].Select(x => (T)x.Content).Except(population).ToList();
292      foreach (var individual in discardedOffspring) {
293        var vertex = GenealogyGraph.GetVertex(individual);
294        GenealogyGraph.RemoveVertex(vertex);
295      }
296
297      return base.Apply();
298    }
299  }
300}
Note: See TracBrowser for help on using the repository browser.