Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Tracking/SymbolicDataAnalysisExpressionTracing.cs @ 11458

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

#1772: HeuristicLab.Problems.DataAnalysis.Symbolic:

  • Merged trunk changes (SymbolicExpressionImporter)
  • Added Passthrough symbol (does not perform an operation, just transfers the input), adjusted interpreter and opcodes accordingly
  • Added diversity preserving crossover
  • Replaced IDistanceCalculator interface with ISymbolicDataAnalysisExpressionSimilarityCalculator and adjusted similarity calculators
  • Refactored tracing, moved functionality to the TraceCalculator (when this is complete the old code will be removed)
File size: 8.3 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;
23using System.Collections.Generic;
24using System.IO;
25using System.Linq;
26using HeuristicLab.Core;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
28using HeuristicLab.EvolutionTracking;
29
30namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
31  public static class SymbolicDataAnalysisExpressionTracing {
32    public static FragmentGraph TraceSubtree(IGenealogyGraphNode<ISymbolicExpressionTree> graphNode, int subtreeIndex) {
33      var graph = new FragmentGraph();
34      var vertices = Trace(graphNode, subtreeIndex).ToList();
35      graph.AddVertices(vertices);
36      return graph;
37    }
38    /// <summary>
39    /// Traces a subtree in a genealogy of individuals, tracking down it's genetic components
40    /// </summary>
41    /// <param name="graphNode">The point in the genealogy where to start the tracing from</param>
42    /// <param name="subtreeIndex">The traced subtree preorder index in the current tree</param>
43    /// <param name="parentNode">The parent node in the fragment graph if there is any</param>
44    /// <returns></returns>
45    private static IEnumerable<FragmentNode> Trace(IGenealogyGraphNode<ISymbolicExpressionTree> graphNode, int subtreeIndex, FragmentNode parentNode = null) {
46      var node = graphNode; // current node
47      var index = subtreeIndex; // current index
48      var parent = parentNode; // current parent
49
50      IGenealogyGraphNode<ISymbolicExpressionTree> n1 = null;
51      int i1 = -1;
52
53      while (true) {
54        if (node == n1 && index == i1)
55          throw new InvalidOperationException("Infinite loop detected");
56
57        n1 = node;
58        i1 = index;
59
60        if (!node.Parents.Any()) {
61          // no tracing if there are no parents, return a fragment node representing the current trace
62          var fragmentNode = new FragmentNode(node.Data) { SubtreeIndex = index };
63          if (parent != null) {
64            var arc = new GenealogyGraphArc(parent, fragmentNode);
65            parent.AddArc(arc);
66            fragmentNode.AddArc(arc);
67          }
68          yield return fragmentNode;
69          break;
70        }
71        var parents = node.Parents.ToList();
72        var fragment = (IFragment<ISymbolicExpressionTreeNode>)node.InArcs.Last().Data;
73
74        if (fragment == null) {
75          // the fragment can be null for two reasons:
76          // 1) the individual is an elite
77          // 2) the crossover/mutation made no changes to the root parent (or there is a bug in fragment identification)
78          if (index >= parents[0].Data.Length) {
79            throw new InvalidOperationException("Index exceeds tree length.");
80          }
81          node = parents[0];
82          continue;
83        }
84
85        var fragmentLength = fragment.Root.GetLength();
86        var tree = node.Data;
87        var subtree = tree.NodeAt(index);
88        var subtreeLength = subtree.GetLength();
89
90        #region mutation tracing
91        if (parents.Count == 1) {
92          // we are tracing a mutation operation
93          var fragmentNode = new FragmentNode(node.Data) {
94            SubtreeIndex = index,
95            FragmentIndex = fragment.Index1
96          };
97          if (parent != null) {
98            var arc = new Arc(parent, fragmentNode);
99            parent.AddArc(arc);
100            fragmentNode.AddArc(arc);
101          }
102          if (node == parents[0])
103            throw new InvalidOperationException("Node == parents[0]");
104
105          node = parents[0];
106
107          if (index == fragment.Index1) {
108            // index stays the same
109          } else if (fragment.Index1 < index) {
110            if (index < fragment.Index1 + fragmentLength) {
111              // in the case of mutation, the fragment could have been introduced via a node replacement
112              // there is no guarantee the subtree exists above this level, therefore the index is set to the fragment index
113              index = fragment.Index1;
114            } else {
115              // subtree outside of fragment
116              index += node.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength;
117            }
118          } else if (index < fragment.Index1) {
119            if (fragment.Index1 < index + subtreeLength) {
120              // subtree contains fragment
121              index = fragment.Index1;
122            } else {
123              // index stays the same
124            }
125          }
126          yield return fragmentNode;
127          if (node == graphNode && index == subtreeIndex)
128            throw new ArgumentException("Infinite recursion detected");
129          var up = Trace(node, index, fragmentNode).ToList(); // force immediate query execution
130          foreach (var v in up) { yield return v; }
131          break;
132        }
133        #endregion
134
135        #region crossover tracing
136        if (parents.Count == 2) {
137          if (node == parents[0])
138            throw new InvalidOperationException("Node == parents[0]");
139          if (node == parents[1])
140            throw new InvalidOperationException("Node == parents[1]");
141          // we are tracing a crossover operation
142          if (fragment.Index1 == index) {
143            node = parents[1]; // take second parent which contains the fragment
144            index = fragment.Index2;
145            continue;
146          }
147
148          if (fragment.Index1 < index) {
149            if (fragment.Index1 + fragmentLength > index) {
150              node = parents[1]; // fragment contains subtree, take second parent
151              index += fragment.Index2 - fragment.Index1; // the subtree has the same index relative to the fragment
152            } else {
153              // fragment distinct from subtree
154              node = parents[0]; // take first parent which contains the subtree
155              index += node.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength; // subtreeIndex must be adjusted according to swapped fragments sizes
156            }
157            continue;
158          }
159
160          if (fragment.Index1 > index) {
161            if (fragment.Index1 < index + subtreeLength) {
162              // subtree contains fragment => branching point in the fragment graph
163              var fragmentNode = new FragmentNode(node.Data) {
164                SubtreeIndex = index,
165                FragmentIndex = fragment.Index1
166              };
167              if (parent != null) {
168                var arc = new GenealogyGraphArc(parent, fragmentNode);
169                parent.AddArc(arc);
170                fragmentNode.AddArc(arc);
171              }
172              yield return fragmentNode;
173
174              if (parents[1].Data.NodeAt(fragment.Index2).GetLength() != fragmentLength) {
175                throw new Exception("Fragment lengths should match!");
176              }
177              // the two paths below ("left" and "right") correspond to the subtree and the fragment, respectively
178              var left = Trace(parents[0], index, fragmentNode); // trace subtree
179              var right = Trace(parents[1], fragment.Index2, fragmentNode); // trace fragment
180              foreach (var v in left.Concat(right)) { yield return v; }
181              break;
182            } else {
183              node = parents[0]; // fragment distinct from subtree: update node, index remains unchanged
184            }
185          }
186        }
187        #endregion
188      }
189    }
190
191    private static string ViewAsText(this ISymbolicExpressionTreeNode root) {
192      var writer = new StringWriter();
193      SymbolicExpressionTreeHierarchicalFormatter.RenderNode(writer, root, string.Empty);
194      return writer.ToString();
195    }
196  }
197}
Note: See TracBrowser for help on using the repository browser.