Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking/3.4/Analyzers/SymbolicExpressionTreeGenealogyAnalyzer.cs @ 8249

Last change on this file since 8249 was 8249, checked in by bburlacu, 12 years ago

#1772: Fixed small bug (correct counting of node ranks) in the SymbolicExpressionTreeGenealogyAnalyzer. Fixed node tool tips in the GenealogyGraphChart.

File size: 17.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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.Drawing;
24using System.Globalization;
25using System.Linq;
26using System.Text;
27using System.Threading;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
32using HeuristicLab.Operators;
33using HeuristicLab.Optimization;
34using HeuristicLab.Parameters;
35using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
36using HeuristicLab.Problems.DataAnalysis;
37using HeuristicLab.Problems.DataAnalysis.Symbolic;
38// type definitions for ease of use
39using CloneMapType = HeuristicLab.Core.ItemDictionary<HeuristicLab.Core.IItem, HeuristicLab.Core.IItem>;
40using TraceMapType = HeuristicLab.Core.ItemDictionary<HeuristicLab.Core.IItem, HeuristicLab.Core.IItemList<HeuristicLab.Core.IItem>>;
41
42namespace HeuristicLab.EvolutionaryTracking {
43  /// <summary>
44  /// An operator that tracks the genealogy of every individual
45  /// </summary>
46  [Item("SymbolicExpressionTreeGenealogyAnalyzer", "An operator that tracks tree lengths of Symbolic Expression Trees")]
47  [StorableClass]
48  public sealed class SymbolicExpressionTreeGenealogyAnalyzer : SingleSuccessorOperator, IAnalyzer {
49    private const string UpdateIntervalParameterName = "UpdateInterval";
50    private const string UpdateCounterParameterName = "UpdateCounter";
51    private const string ResultsParameterName = "Results";
52    private const string ElitesParameterName = "Elites";
53    private const string GenerationsParameterName = "Generations";
54    private const string MaximumGenerationsParameterName = "MaximumGenerations";
55    private const string MaximumSelectionPressureParameterName = "MaximumSelectionPressure";
56    private const string SelectionPressureParameterName = "SelectionPressure";
57    private const string GlobalTraceMapParameterName = "GlobalTraceMap";
58    private const string GlobalCloneMapParameterName = "GlobalCloneMap";
59    private const string GlobalFragmentMapParameterName = "GlobalFragmentMap";
60    private const string PopulationGraphResultParameterName = "PopulationGraph";
61    private const string PopulationGraphResultParameterDescription = "Individual lineages";
62    private const string SymbolicExpressionInterpreterParameterName = "SymbolicExpressionTreeInterpreter";
63    private const string SymbolicRegressionProblemDataParameterName = "ProblemData";
64    private const string SymbolicDataAnalysisProblemEvaluatorParameterName = "Evaluator";
65
66    #region Parameter properties
67    public ValueParameter<IntValue> UpdateIntervalParameter {
68      get { return (ValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
69    }
70    public ValueParameter<IntValue> UpdateCounterParameter {
71      get { return (ValueParameter<IntValue>)Parameters[UpdateCounterParameterName]; }
72    }
73    public LookupParameter<ResultCollection> ResultsParameter {
74      get { return (LookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
75    }
76    public LookupParameter<IntValue> ElitesParameter {
77      get { return (LookupParameter<IntValue>)Parameters[ElitesParameterName]; }
78    }
79    public LookupParameter<IntValue> GenerationsParameter {
80      get { return (LookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
81    }
82    public LookupParameter<IntValue> MaximumGenerationsParameter {
83      get { return (LookupParameter<IntValue>)Parameters[MaximumGenerationsParameterName]; }
84    }
85    public LookupParameter<DoubleValue> SelectionPressureParameter {
86      get { return (LookupParameter<DoubleValue>)Parameters[SelectionPressureParameterName]; }
87    }
88    public LookupParameter<DoubleValue> MaximumSelectionPressureParameter {
89      get { return (LookupParameter<DoubleValue>)Parameters[MaximumSelectionPressureParameterName]; }
90    }
91    // problem data, interpreter and evaluator
92    public LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter> SymbolicExpressionInterpreterParameter {
93      get { return (LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[SymbolicExpressionInterpreterParameterName]; }
94    }
95    public LookupParameter<RegressionProblemData> SymbolicRegressionProblemDataParameter {
96      get { return (LookupParameter<RegressionProblemData>)Parameters[SymbolicRegressionProblemDataParameterName]; }
97    }
98    public LookupParameter<IEvaluator> SymbolicDataAnalysisProblemEvaluatorParameter {
99      get { return (LookupParameter<IEvaluator>)Parameters[SymbolicDataAnalysisProblemEvaluatorParameterName]; }
100    }
101    // genealogy global parameters
102    public LookupParameter<TraceMapType> GlobalTraceMapParameter {
103      get { return (LookupParameter<TraceMapType>)Parameters[GlobalTraceMapParameterName]; }
104    }
105    public LookupParameter<CloneMapType> GlobalCloneMapParameter {
106      get { return (LookupParameter<CloneMapType>)Parameters[GlobalCloneMapParameterName]; }
107    }
108    public LookupParameter<CloneMapType> GlobalFragmentMapParameter {
109      get { return (LookupParameter<CloneMapType>)Parameters[GlobalFragmentMapParameterName]; }
110    }
111    #endregion
112    #region Properties
113    public bool EnabledByDefault {
114      get { return true; }
115    }
116    public IntValue UpdateInterval {
117      get { return UpdateIntervalParameter.Value; }
118    }
119    public IntValue UpdateCounter {
120      get { return UpdateCounterParameter.Value; }
121    }
122    public ResultCollection Results {
123      get { return ResultsParameter.ActualValue; }
124    }
125    public IntValue Elites {
126      get { return ElitesParameter.ActualValue; }
127    }
128    public IntValue Generations {
129      get { return GenerationsParameter.ActualValue; }
130    }
131    public IntValue MaximumGenerations {
132      get { return MaximumGenerationsParameter.ActualValue; }
133    }
134    public DoubleValue SelectionPressure {
135      get { return SelectionPressureParameter.ActualValue; }
136    }
137    public DoubleValue MaximumSelectionPressure {
138      get { return MaximumSelectionPressureParameter.ActualValue; }
139    }
140    public CloneMapType GlobalCloneMap {
141      get { return GlobalCloneMapParameter.ActualValue; }
142    }
143    public TraceMapType GlobalTraceMap {
144      get { return GlobalTraceMapParameter.ActualValue; }
145    }
146    public CloneMapType GlobalFragmentMap {
147      get { return GlobalFragmentMapParameter.ActualValue; }
148    }
149    public SymbolicDataAnalysisExpressionTreeInterpreter SymbolicExpressionInterpreter {
150      get { return SymbolicExpressionInterpreterParameter.ActualValue; }
151    }
152    public RegressionProblemData SymbolicRegressionProblemData {
153      get { return SymbolicRegressionProblemDataParameter.ActualValue; }
154    }
155    public IEvaluator SymbolicDataAnalysisEvaluator {
156      get { return SymbolicDataAnalysisProblemEvaluatorParameter.ActualValue; }
157    }
158    #endregion
159
160    [StorableConstructor]
161    private SymbolicExpressionTreeGenealogyAnalyzer(bool deserializing)
162      : base() {
163    }
164    private SymbolicExpressionTreeGenealogyAnalyzer(SymbolicExpressionTreeGenealogyAnalyzer original, Cloner cloner)
165      : base(original, cloner) {
166    }
167    public override IDeepCloneable Clone(Cloner cloner) {
168      return new SymbolicExpressionTreeGenealogyAnalyzer(this, cloner);
169    }
170    public SymbolicExpressionTreeGenealogyAnalyzer()
171      : base() {
172      Parameters.Add(new LookupParameter<IntValue>(ElitesParameterName, "The number of elites."));
173      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
174      Parameters.Add(new LookupParameter<IntValue>(MaximumGenerationsParameterName, "The maximum number of generations"));
175      Parameters.Add(new LookupParameter<DoubleValue>(SelectionPressureParameterName, "The current selection (ony for OSGA)"));
176      Parameters.Add(new LookupParameter<DoubleValue>(MaximumSelectionPressureParameterName, "Maximum allowed value of selection pressure."));
177      Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1)));
178      Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, "The value which counts how many times the operator was called since the last update", new IntValue(0)));
179      Parameters.Add(new LookupParameter<TraceMapType>(GlobalTraceMapParameterName, "A global cache containing the whole genealogy."));
180      Parameters.Add(new LookupParameter<CloneMapType>(GlobalCloneMapParameterName, "A global map keeping track of trees and their clones (made during selection)."));
181      Parameters.Add(new LookupParameter<CloneMapType>(GlobalFragmentMapParameterName, "A global map keeping track of tree fragments received via crossover."));
182      Parameters.Add(new ValueLookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
183      Parameters.Add(new LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter>(SymbolicExpressionInterpreterParameterName, "Interpreter for symbolic expression trees"));
184      Parameters.Add(new LookupParameter<RegressionProblemData>(SymbolicRegressionProblemDataParameterName, "The symbolic data analysis problem."));
185      Parameters.Add(new LookupParameter<IEvaluator>(SymbolicDataAnalysisProblemEvaluatorParameterName, "The fitness evaluator"));
186
187      UpdateCounterParameter.Hidden = true;
188      UpdateIntervalParameter.Hidden = true;
189    }
190
191    [StorableHook(HookType.AfterDeserialization)]
192    private void AfterDeserialization() {
193      // check if all the parameters are present and accounted for
194      if (!Parameters.ContainsKey(UpdateIntervalParameterName)) {
195        Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1)));
196      }
197      if (Parameters.ContainsKey(UpdateCounterParameterName)) return;
198      Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, "The value which counts how many times the operator was called since the last update", new IntValue(0)));
199      UpdateCounterParameter.Hidden = true;
200    }
201
202    #region IStatefulItem members
203    public override void InitializeState() {
204      base.InitializeState();
205      UpdateCounter.Value = 0;
206    }
207
208    public override void ClearState() {
209      base.ClearState();
210      UpdateCounter.Value = 0;
211    }
212    #endregion
213
214    public override IOperation Apply() {
215      UpdateCounter.Value++;
216      // the analyzer runs periodically, every 'updateInterval' times
217      if (UpdateCounter.Value == UpdateInterval.Value) {
218        UpdateCounter.Value = 0; // reset counter
219
220        var gScope = ExecutionContext.Scope;
221        while (gScope.Parent != null) gScope = gScope.Parent;
222        SymbolicExpressionTreeGenealogyGraph graph;
223        if (!Results.ContainsKey(PopulationGraphResultParameterName)) {
224          graph = new SymbolicExpressionTreeGenealogyGraph();
225          Results.Add(new Result(PopulationGraphResultParameterName, PopulationGraphResultParameterDescription, graph));
226        } else {
227          graph = (SymbolicExpressionTreeGenealogyGraph)(Results[PopulationGraphResultParameterName].Value);
228        }
229        // get tree quality values (Key => Individual, Value => Quality)
230        var scopes = (from s in gScope.SubScopes
231                      let individual = s.Variables.First().Value
232                      let quality = (DoubleValue)s.Variables["Quality"].Value
233                      orderby quality.Value descending
234                      select new { Tree = (ISymbolicExpressionTree)individual, Quality = quality.Value }).ToList();
235
236        // add all individuals to the evolutionary graph
237        int generation = Generations.Value;
238        // add nodes to genealogy graph
239        for (int i = 0; i != scopes.Count; ++i) {
240          var indiv = scopes[i].Tree;
241          var label = (generation * scopes.Count + i + 1).ToString(CultureInfo.InvariantCulture);
242          if (!graph.HasNode(indiv)) {
243            var node = new GenealogyGraphNode(indiv) { Label = label };
244            graph.AddNode(node);
245            // node metadata
246            graph[node].Ranks.Add(generation);
247            graph[node].Quality = scopes[i].Quality;
248            graph[node].IsElite = i < Elites.Value;
249          } else {
250            var node = graph.GetNode(indiv);
251            graph[node].Ranks.Add(generation);
252          }
253          if (generation == 0) continue;
254          if (!GlobalTraceMap.ContainsKey(indiv)) continue;
255
256          var parents = GlobalTraceMap[indiv].Cast<ISymbolicExpressionTree>();
257          foreach (var parent in parents) {
258            object data = ((GenericWrapper<SymbolicExpressionTreeNode>)GlobalFragmentMap[indiv]).Content;
259            if (GlobalTraceMap.ContainsKey(parent)) {
260              var node = new GenealogyGraphNode(parent) { Label = "X" };
261              graph.AddNode(node);
262              graph[node].Quality = Evaluate(parent);
263              graph[node].Ranks.Add(generation - 0.5);
264              var pp = GlobalTraceMap[parent].Cast<SymbolicExpressionTree>();
265              foreach (var p in pp) {
266                data = ((GenericWrapper<SymbolicExpressionTreeNode>)GlobalFragmentMap[parent]).Content;
267                graph.AddArc(p, parent, null, data);
268              }
269            }
270            graph.AddArc(parent, indiv, null, data);
271          }
272        }
273        // clear trace and clone maps in preparation for the next generation
274        if (generation == 0) return base.Apply();
275        if (this.Successor == null || !(this.Successor is SymbolicExpressionTreeFragmentsAnalyzer)) {
276          GlobalTraceMap.Clear();
277          GlobalCloneMap.Clear();
278          GlobalFragmentMap.Clear();
279        }
280      }
281      return base.Apply();
282    }
283
284    private double Evaluate(ISymbolicExpressionTree tree) {
285      // we perform evaluation by adding a temporary subscope with the tree in it, and calling evaluator.Apply()
286      var subScope = new Scope();
287      // inject expected variables into the subscope
288      subScope.Variables.Add(new Core.Variable("SymbolicExpressionTree", tree));
289      ExecutionContext.Scope.SubScopes.Add(subScope);
290      var context = new Core.ExecutionContext(ExecutionContext, SymbolicDataAnalysisEvaluator, subScope);
291      SymbolicDataAnalysisEvaluator.Execute(context, new CancellationToken());
292      // get the quality
293      double quality = ((DoubleValue)subScope.Variables["Quality"].Value).Value;
294      // remove the subscope
295      ExecutionContext.Scope.SubScopes.Remove(subScope);
296      return quality;
297    }
298
299    #region Export to dot file
300    private static void WriteDot(string path, SymbolicExpressionTreeGenealogyGraph graph) {
301      using (var file = new System.IO.StreamWriter(path)) {
302        string nl = Environment.NewLine;
303        file.WriteLine("digraph \"lineage " + graph.AverageDegree.ToString(CultureInfo.InvariantCulture) + "\" {" + nl + "ratio=auto;" + nl + "mincross=2.0");
304        file.WriteLine("\tnode [shape=circle,label=\"\",style=filled]");
305
306        foreach (var node in graph.Values) {
307          var color = Color.FromArgb((int)((1 - graph[node].Quality) * 255), (int)(graph[node].Quality * 255), 0);
308          string fillColor = String.Format("#{0:x2}{1:x2}{2:x2}", color.R, color.G, color.B);
309          string shape = "circle";
310          if (graph[node].IsElite)
311            shape = "doublecircle";
312          file.WriteLine("\t\"" + node.Id + "\" [shape=" + shape + ",fillcolor=\"" + fillColor + "\",label=\"" + node.Label + "\"];");
313          if (node.InEdges == null)
314            continue;
315          foreach (var edge in node.InEdges) {
316            //var edgeStyle = node.InEdges.Count == 1 ? "dashed" : String.Empty;
317            var edgeStyle = String.Empty;
318            file.WriteLine("\t\"" + edge.Target.Id + "\" -> \"" + node.Id + "\" [arrowsize=.5, color=\"" + fillColor + "\", style=\"" + edgeStyle + "\"];");
319          }
320        }
321        foreach (var g in graph.Values.GroupBy(x => graph[x].Ranks[0])) {
322          var sb = new StringBuilder();
323          sb.Append("\t{rank=same;");
324          foreach (var node in g)
325            sb.Append("\"" + node.Id + "\" ");
326          sb.Append("}\n");
327          file.Write(sb.ToString());
328        }
329        file.WriteLine("}");
330      }
331    }
332    #endregion
333  }
334}
Note: See TracBrowser for help on using the repository browser.