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

Last change on this file since 10884 was 10884, checked in by bburlacu, 8 years ago

#1772: Added license headers where they were missing. Introduced an id map to the DirectedGraph to get graph vertices based on the id injected in the scopes by the genealogy analyzer.

File size: 14.8 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    public string CrossoverParentsParameterName { get; set; }
57    public string CrossoverChildParameterName { get; set; }
58    public string ManipulatorChildParameterName { get; set; }
59
60    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
61      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
62    }
63
64    public IScopeTreeLookupParameter<T> PopulationParameter {
65      get { return (IScopeTreeLookupParameter<T>)Parameters[PopulationParameterName]; }
66    }
67
68    public IValueParameter<ICrossoverOperator<T>> BeforeCrossoverOperatorParameter {
69      get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[BeforeCrossoverOperatorParameterName]; }
70    }
71    public IValueParameter<ICrossoverOperator<T>> AfterCrossoverOperatorParameter {
72      get { return (IValueParameter<ICrossoverOperator<T>>)Parameters[AfterCrossoverOperatorParameterName]; }
73    }
74    public IValueParameter<IManipulatorOperator<T>> BeforeManipulatorOperatorParameter {
75      get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[BeforeManipulatorOperatorParameterName]; }
76    }
77    public IValueParameter<IManipulatorOperator<T>> AfterManipulatorOperatorParameter {
78      get { return (IValueParameter<IManipulatorOperator<T>>)Parameters[AfterManipulatorOperatorParameterName]; }
79    }
80
81    #region parameter properties
82    public ILookupParameter<ResultCollection> ResultsParameter {
83      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
84    }
85    public ILookupParameter<IntValue> GenerationsParameter {
86      get { return (ILookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
87    }
88    public IValueParameter<BoolValue> EnableCrossoverTrackingParameter {
89      get { return (IValueParameter<BoolValue>)Parameters[EnableCrossoverTrackingParameterName]; }
90    }
91    public IValueParameter<BoolValue> EnableManipulatorTrackingParameter {
92      get { return (IValueParameter<BoolValue>)Parameters[EnableManipulatorTrackingParameterName]; }
93    }
94    public IValueParameter<BoolValue> EnableSolutionCreatorTrackingParameter {
95      get { return (IValueParameter<BoolValue>)Parameters[EnableSolutionCreatorTrackingParameterName]; }
96    }
97    public ILookupParameter<ICrossover> CrossoverParameter {
98      get { return (ILookupParameter<ICrossover>)Parameters[CrossoverParameterName]; }
99    }
100    public ILookupParameter<IManipulator> ManipulatorParameter {
101      get { return (ILookupParameter<IManipulator>)Parameters[ManipulatorParameterName]; }
102    }
103
104    public ILookupParameter<ISolutionCreator> SolutionCreatorParameter {
105      get { return (ILookupParameter<ISolutionCreator>)Parameters[SolutionCreatorParameterName]; }
106    }
107    #endregion
108
109    #region properties
110    public ICrossover Crossover {
111      get { return CrossoverParameter.ActualValue; }
112    }
113    public IManipulator Manipulator {
114      get { return ManipulatorParameter.ActualValue; }
115    }
116    public ICrossoverOperator<T> BeforeCrossoverOperator {
117      get { return BeforeCrossoverOperatorParameter.Value; }
118    }
119    public ICrossoverOperator<T> AfterCrossoverOperator {
120      get { return AfterCrossoverOperatorParameter.Value; }
121    }
122    public IManipulatorOperator<T> BeforeManipulatorOperator {
123      get { return BeforeManipulatorOperatorParameter.Value; }
124    }
125    public IManipulatorOperator<T> AfterManipulatorOperator {
126      get { return AfterManipulatorOperatorParameter.Value; }
127    }
128    public ISolutionCreator SolutionCreator {
129      get { return SolutionCreatorParameter.ActualValue; }
130    }
131    public BoolValue EnableCrossoverTracking {
132      get { return EnableCrossoverTrackingParameter.Value; }
133    }
134    public BoolValue EnableManipulatorTracking {
135      get { return EnableManipulatorTrackingParameter.Value; }
136    }
137    public BoolValue EnableSolutionCreatorTracking {
138      get { return EnableSolutionCreatorTrackingParameter.Value; }
139    }
140    public ResultCollection Results {
141      get { return ResultsParameter.ActualValue; }
142    }
143    public IntValue Generations {
144      get { return GenerationsParameter.ActualValue; }
145    }
146    public IGenealogyGraph<T> GenealogyGraph {
147      get {
148        IResult result;
149        if (!Results.ContainsKey(PopulationGraphParameterName)) {
150          result = new Result(PopulationGraphParameterName, new GenealogyGraph<T>());
151          Results.Add(result);
152        } else {
153          result = Results[PopulationGraphParameterName];
154        }
155        var graph = (IGenealogyGraph<T>)result.Value;
156        return graph;
157      }
158    }
159    #endregion
160
161    public GenealogyAnalyzer() {
162      // the instrumented operators
163      Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
164      Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
165      Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
166      // the analyzer parameters
167      Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
168      Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
169      Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
170      // parameters required by the analyzer to do its work
171      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
172      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
173      Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
174      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
175      Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(BeforeCrossoverOperatorParameterName));
176      Parameters.Add(new ValueParameter<ICrossoverOperator<T>>(AfterCrossoverOperatorParameterName));
177      Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(BeforeManipulatorOperatorParameterName));
178      Parameters.Add(new ValueParameter<IManipulatorOperator<T>>(AfterManipulatorOperatorParameterName));
179    }
180    public override IDeepCloneable Clone(Cloner cloner) {
181      return new GenealogyAnalyzer<T>(this, cloner);
182    }
183    protected GenealogyAnalyzer(GenealogyAnalyzer<T> original, Cloner cloner)
184      : base(original, cloner) {
185    }
186    [StorableHook(HookType.AfterDeserialization)]
187    private void AfterDeserialization() {
188      // the instrumented operators
189      if (!Parameters.ContainsKey(CrossoverParameterName))
190        Parameters.Add(new LookupParameter<ICrossover>(CrossoverParameterName, "The crossover operator."));
191      if (!Parameters.ContainsKey(ManipulatorParameterName))
192        Parameters.Add(new LookupParameter<IManipulator>(ManipulatorParameterName, "The manipulator operator."));
193      if (!Parameters.ContainsKey(SolutionCreatorParameterName))
194        Parameters.Add(new LookupParameter<ISolutionCreator>(SolutionCreatorParameterName, "The solution creator operator."));
195      // the analyzer parameters
196      if (!Parameters.ContainsKey(EnableCrossoverTrackingParameterName))
197        Parameters.Add(new ValueParameter<BoolValue>(EnableCrossoverTrackingParameterName, new BoolValue(true)));
198      if (!Parameters.ContainsKey(EnableManipulatorTrackingParameterName))
199        Parameters.Add(new ValueParameter<BoolValue>(EnableManipulatorTrackingParameterName, new BoolValue(true)));
200      if (!Parameters.ContainsKey(EnableSolutionCreatorTrackingParameterName))
201        Parameters.Add(new ValueParameter<BoolValue>(EnableSolutionCreatorTrackingParameterName, new BoolValue(true)));
202      // parameters required by the analyzer to do its work
203      if (!Parameters.ContainsKey(GenerationsParameterName))
204        Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
205      if (!Parameters.ContainsKey(ResultsParameterName))
206        Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName));
207      if (!Parameters.ContainsKey(PopulationParameterName)) {
208        Parameters.Add(new ScopeTreeLookupParameter<T>(PopulationParameterName, "The population of individuals."));
209      }
210      if (!Parameters.ContainsKey(QualityParameterName)) {
211        Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
212      }
213    }
214
215    public bool EnabledByDefault {
216      get { return false; }
217    }
218
219    private void ConfigureTrackingOperators() {
220      // at the beginning we add the before/after operators to the instrumented operators
221      if (Crossover != null) {
222        var instrumentedCrossover = (InstrumentedOperator)Crossover;
223        instrumentedCrossover.AfterExecutionOperators.Clear();
224        instrumentedCrossover.BeforeExecutionOperators.Clear();
225
226        if (EnableCrossoverTracking.Value) {
227          if (BeforeCrossoverOperator != null) {
228            instrumentedCrossover.BeforeExecutionOperators.Add(BeforeCrossoverOperator);
229          }
230          if (AfterCrossoverOperator != null) {
231            instrumentedCrossover.AfterExecutionOperators.Add(AfterCrossoverOperator);
232          }
233        }
234      }
235
236      if (Manipulator != null) {
237        var instrumentedManipulator = (InstrumentedOperator)Manipulator;
238        instrumentedManipulator.AfterExecutionOperators.Clear();
239        instrumentedManipulator.BeforeExecutionOperators.Clear();
240
241        if (EnableManipulatorTracking.Value) {
242          if (BeforeManipulatorOperator != null) {
243            instrumentedManipulator.BeforeExecutionOperators.Add(BeforeManipulatorOperator);
244          }
245          if (AfterManipulatorOperator != null) {
246            instrumentedManipulator.AfterExecutionOperators.Add(AfterManipulatorOperator);
247          }
248        }
249      }
250    }
251
252    public override IOperation Apply() {
253      var population = PopulationParameter.ActualValue.ToList();
254      var qualities = QualityParameter.ActualValue.ToList();
255
256      if (Generations.Value == 0) {
257        ConfigureTrackingOperators();
258
259        for (int i = 0; i < population.Count; ++i) {
260          var individual = population[i];
261          var vertex = new GenealogyGraphNode<T> { Content = individual, Rank = Generations.Value, };
262          GenealogyGraph.AddVertex(vertex);
263          // save the vertex id in the individual scope (so that we can identify graph indices)
264          ExecutionContext.Scope.SubScopes[i].Variables.Add(new Variable("Id", new StringValue(vertex.Id)));
265        }
266      } else {
267        var elite = population.FirstOrDefault(x => GenealogyGraph.Contains(x));
268        if (elite != null) {
269          var vertex = new GenealogyGraphNode<T> {
270            Content = (T)elite.Clone(),
271            Rank = Generations.Value,
272            IsElite = true
273          };
274          // add new vertex to the graph
275          GenealogyGraph.AddVertex(vertex);
276          // swap content between current vertex and previous vertex
277          var previousVertex = (IGenealogyGraphNode<T>)GenealogyGraph[elite];
278          var tmp = vertex.Content;
279          vertex.Content = previousVertex.Content;
280          previousVertex.Content = tmp;
281          // adjust graph content map
282          GenealogyGraph[vertex.Content] = vertex;
283          GenealogyGraph[previousVertex.Content] = previousVertex;
284          // connect current elite with previous elite
285          previousVertex.AddForwardArc(vertex);
286          vertex.AddReverseArc(previousVertex);
287          vertex.Id = previousVertex.Id; // another way would be to introduce the vertex.Id into the scope of the elite
288          vertex.Quality = previousVertex.Quality;
289
290          if (previousVertex.InArcs.Any()) {
291            vertex.InArcs.Last().Data = previousVertex.InArcs.Last().Data; // save the fragment in case there is one
292          }
293        }
294      }
295      // update qualities
296      for (int i = 0; i < population.Count; ++i) {
297        var vertex = (IGenealogyGraphNode)GenealogyGraph[population[i]];
298        vertex.Quality = qualities[i].Value;
299      }
300
301      return base.Apply();
302    }
303  }
304}
Note: See TracBrowser for help on using the repository browser.