Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1772: Separated instance-specific attributes of graph node objects from the generic genealogy graph, into metadata objects kept by the specific graph class which corresponds to the specific problem instance (so for instance the SymbolicExpressionTreeGenealogyGraph will keep info about node ranks and qualities etc because that info is specific to symbolic data analysis problems).

File size: 16.9 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) {
244              Label = label,
245            };
246            graph.AddNode(node);
247            // node metadata
248            graph[node].Ranks.Add(generation);
249            graph[node].Quality = scopes[i].Quality;
250            graph[node].IsElite = i < Elites.Value;
251          }
252          if (generation == 0) continue;
253          if (!GlobalTraceMap.ContainsKey(indiv)) continue;
254
255          var parents = GlobalTraceMap[indiv].Cast<ISymbolicExpressionTree>();
256          foreach (var parent in parents) {
257            object data = ((GenericWrapper<SymbolicExpressionTreeNode>)GlobalFragmentMap[indiv]).Content;
258            if (GlobalTraceMap.ContainsKey(parent)) {
259              var node = new GenealogyGraphNode(parent) { Label = "X" };
260              graph.AddNode(node);
261              graph[node].Quality = Evaluate(parent);
262              graph[node].Ranks.Add(generation - 0.5);
263              var pp = GlobalTraceMap[parent].Cast<SymbolicExpressionTree>();
264              foreach (var p in pp) {
265                data = ((GenericWrapper<SymbolicExpressionTreeNode>)GlobalFragmentMap[parent]).Content;
266                graph.AddArc(p, parent, null, data);
267              }
268            }
269            graph.AddArc(parent, indiv, null, data);
270          }
271        }
272        // clear trace and clone maps in preparation for the next generation
273        if (generation == 0) return base.Apply();
274        if (this.Successor == null || !(this.Successor is SymbolicExpressionTreeFragmentsAnalyzer)) {
275          GlobalTraceMap.Clear();
276          GlobalCloneMap.Clear();
277          GlobalFragmentMap.Clear();
278        }
279      }
280      return base.Apply();
281    }
282
283    private double Evaluate(ISymbolicExpressionTree tree) {
284      // we perform evaluation by adding a temporary subscope with the tree in it, and calling evaluator.Apply()
285      var subScope = new Scope();
286      // inject expected variables into the subscope
287      subScope.Variables.Add(new Core.Variable("SymbolicExpressionTree", tree));
288      ExecutionContext.Scope.SubScopes.Add(subScope);
289      var context = new Core.ExecutionContext(ExecutionContext, SymbolicDataAnalysisEvaluator, subScope);
290      SymbolicDataAnalysisEvaluator.Execute(context, new CancellationToken());
291      // get the quality
292      double quality = ((DoubleValue)subScope.Variables["Quality"].Value).Value;
293      // remove the subscope
294      ExecutionContext.Scope.SubScopes.Remove(subScope);
295      return quality;
296    }
297
298    #region Export to dot file
299    private static void WriteDot(string path, SymbolicExpressionTreeGenealogyGraph graph) {
300      using (var file = new System.IO.StreamWriter(path)) {
301        string nl = Environment.NewLine;
302        file.WriteLine("digraph \"lineage " + graph.AverageDegree.ToString(CultureInfo.InvariantCulture) + "\" {" + nl + "ratio=auto;" + nl + "mincross=2.0");
303        file.WriteLine("\tnode [shape=circle,label=\"\",style=filled]");
304
305        foreach (var node in graph.Values) {
306          var color = Color.FromArgb((int)((1 - graph[node].Quality) * 255), (int)(graph[node].Quality * 255), 0);
307          string fillColor = String.Format("#{0:x2}{1:x2}{2:x2}", color.R, color.G, color.B);
308          string shape = "circle";
309          if (graph[node].IsElite)
310            shape = "doublecircle";
311          file.WriteLine("\t\"" + node.Id + "\" [shape=" + shape + ",fillcolor=\"" + fillColor + "\",label=\"" + node.Label + "\"];");
312          if (node.InEdges == null)
313            continue;
314          foreach (var edge in node.InEdges) {
315            //var edgeStyle = node.InEdges.Count == 1 ? "dashed" : String.Empty;
316            var edgeStyle = String.Empty;
317            file.WriteLine("\t\"" + edge.Target.Id + "\" -> \"" + node.Id + "\" [arrowsize=.5, color=\"" + fillColor + "\", style=\"" + edgeStyle + "\"];");
318          }
319        }
320        foreach (var g in graph.Values.GroupBy(x => graph[x].Ranks[0])) {
321          var sb = new StringBuilder();
322          sb.Append("\t{rank=same;");
323          foreach (var node in g)
324            sb.Append("\"" + node.Id + "\" ");
325          sb.Append("}\n");
326          file.Write(sb.ToString());
327        }
328        file.WriteLine("}");
329      }
330    }
331    #endregion
332  }
333}
Note: See TracBrowser for help on using the repository browser.