Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1772: SymbolicDataAnalysisExpressionTracing: added more detailed comments; enforced a safer behaviour in the case of mutation when the traced subtree is contained inside the mutated tree fragment.

File size: 8.0 KB
RevLine 
[10884]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
[10755]22using System;
[10752]23using System.Collections.Generic;
24using System.IO;
25using System.Linq;
[11253]26using HeuristicLab.Core;
[10752]27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
28using HeuristicLab.EvolutionTracking;
29
[10827]30namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[10752]31  public static class SymbolicDataAnalysisExpressionTracing {
[10888]32    public static FragmentGraph TraceSubtree(IGenealogyGraphNode<ISymbolicExpressionTree> graphNode, int subtreeIndex) {
[11233]33      var graph = new FragmentGraph();
[11318]34      var vertices = Trace(graphNode, subtreeIndex).ToList();
35      graph.AddVertices(vertices);
[10752]36      return graph;
37    }
[10888]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) {
[10752]46      var node = graphNode; // current node
47      var index = subtreeIndex; // current index
48      var parent = parentNode; // current parent
[10755]49
[10752]50      while (true) {
[10755]51        if (!node.Parents.Any()) {
[11318]52          // no tracing if there are no parents, return a fragment node representing the current trace
53          var fragmentNode = new FragmentNode(node) { SubtreeIndex = index };
[10755]54          if (parent != null) {
[10888]55            var arc = new Arc(parent, fragmentNode);
[11233]56            parent.AddArc(arc);
57            fragmentNode.AddArc(arc);
[10755]58          }
[11318]59          yield return fragmentNode;
[10755]60          break;
[10752]61        }
[10827]62        var parents = node.Parents.ToList();
[11350]63        var fragment = (IFragment<ISymbolicExpressionTreeNode>)node.InArcs.Last().Data;
64
65        if (fragment == null) {
[11388]66          // the fragment can be null for two reasons:
67          // 1) the individual is an elite
68          // 2) the crossover/mutation made no changes to the root parent (or there is a bug in fragment identification)
69          if (index >= parents[0].Data.Length) {
70            throw new InvalidOperationException("Index exceeds tree length.");
71          }
[10827]72          node = parents[0];
[10752]73          continue;
[10827]74        }
[11318]75
[10827]76        var fragmentLength = fragment.Root.GetLength();
[11253]77        var tree = node.Data;
[10755]78        var subtree = tree.NodeAt(index);
79        var subtreeLength = subtree.GetLength();
80
[10888]81        #region mutation tracing
[10827]82        if (parents.Count == 1) {
83          // we are tracing a mutation operation
[11233]84          var fragmentNode = new FragmentNode(node) {
[10888]85            SubtreeIndex = index,
86            FragmentIndex = fragment.Index1
[10827]87          };
88          if (parent != null) {
[10888]89            var arc = new Arc(parent, fragmentNode);
[11233]90            parent.AddArc(arc);
91            fragmentNode.AddArc(arc);
[10827]92          }
[10888]93          node = parents[0];
94          if (subtreeIndex == fragment.Index1) {
95            // index stays the same
96          } else if (fragment.Index1 < subtreeIndex) {
97            if (subtreeIndex < fragment.Index1 + fragmentLength) {
[11388]98              // in the case of mutation, the fragment could have been introduced via a node replacement
99              // there is no guarantee the subtree exists above this level, therefore the index is set to the fragment index
100              index = fragment.Index1;
[10888]101            } else {
[11388]102              // subtree outside of fragment
[11253]103              index += node.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength;
[10888]104            }
105          } else if (subtreeIndex < fragment.Index1) {
106            if (fragment.Index1 < subtreeIndex + subtreeLength) {
107              // subtree contains fragment
108              index = fragment.Index1;
109            } else {
110              // index stays the same
111            }
112          }
113
[10827]114          yield return fragmentNode;
[11388]115          var up = Trace(node, index, fragmentNode); // force immediate query execution
[10827]116          foreach (var v in up) { yield return v; }
117          break;
118        }
[10888]119        #endregion
[10755]120
[10888]121        #region crossover tracing
[10827]122        if (parents.Count == 2) {
123          // we are tracing a crossover operation
124          if (fragment.Index1 == index) {
125            node = parents[1]; // take second parent which contains the fragment
126            index = fragment.Index2;
127            continue;
[10752]128          }
[10827]129
130          if (fragment.Index1 < index) {
131            if (fragment.Index1 + fragmentLength > index) {
132              node = parents[1]; // fragment contains subtree, take second parent
133              index += fragment.Index2 - fragment.Index1; // the subtree has the same index relative to the fragment
134            } else {
135              // fragment distinct from subtree
136              node = parents[0]; // take first parent which contains the subtree
[11253]137              index += node.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength; // subtreeIndex must be adjusted according to swapped fragments sizes
[10755]138            }
[10827]139            continue;
140          }
[10755]141
[10827]142          if (fragment.Index1 > index) {
143            if (fragment.Index1 < index + subtreeLength) {
[11318]144              // subtree contains fragment => branching point in the fragment graph
[11233]145              var fragmentNode = new FragmentNode(node) {
[10888]146                SubtreeIndex = index,
147                FragmentIndex = fragment.Index1
[10827]148              };
149              if (parent != null) {
[10888]150                var arc = new Arc(parent, fragmentNode);
[11233]151                parent.AddArc(arc);
152                fragmentNode.AddArc(arc);
[10827]153              }
154              yield return fragmentNode;
[10755]155
[11253]156              if (parents[1].Data.NodeAt(fragment.Index2).GetLength() != fragmentLength) {
[10827]157                throw new Exception("Fragment lengths should match!");
158              }
159              // the two paths below ("left" and "right") correspond to the subtree and the fragment, respectively
160              var left = Trace(parents[0], index, fragmentNode); // trace subtree
161              var right = Trace(parents[1], fragment.Index2, fragmentNode); // trace fragment
162              foreach (var v in left.Concat(right)) { yield return v; }
163              break;
164            } else {
165              node = parents[0]; // fragment distinct from subtree: update node, index remains unchanged
[10755]166            }
[10752]167          }
168        }
[10888]169        #endregion
[10752]170      }
171    }
172
173    private static string ViewAsText(this ISymbolicExpressionTreeNode root) {
174      var writer = new StringWriter();
175      SymbolicExpressionTreeHierarchicalFormatter.RenderNode(writer, root, string.Empty);
176      return writer.ToString();
177    }
178    #region some helper methods for shortening the tracing code
179    private static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
180      return NodeAt(tree.Root, position);
181    }
182    private static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
183      return root.IterateNodesPrefix().ElementAt(position);
184    }
185    #endregion
186  }
187}
Note: See TracBrowser for help on using the repository browser.