Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Tracking/TraceCalculator.cs @ 11473

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

#1772: Finished the TraceCalculator, added tracing for mutation operations.

File size: 9.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using HeuristicLab.Common;
5using HeuristicLab.Core;
6using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
7using HeuristicLab.EvolutionTracking;
8using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
9
10namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
11  [Item("TraceCalculator", "Walks a genealogy graph and produces a trace of the specified subtree")]
12  [StorableClass]
13  public class TraceCalculator : Item {
14    private readonly IGenealogyGraph<ISymbolicExpressionTree> traceGraph;
15    private readonly Dictionary<IGenealogyGraphNode<ISymbolicExpressionTree>, Tuple<int, int>> traceMap;
16
17    public IGenealogyGraph<ISymbolicExpressionTree> TraceGraph { get { return traceGraph; } }
18
19    public TraceCalculator() {
20      traceGraph = new GenealogyGraph<ISymbolicExpressionTree>();
21      traceMap = new Dictionary<IGenealogyGraphNode<ISymbolicExpressionTree>, Tuple<int, int>>();
22    }
23
24    protected TraceCalculator(TraceCalculator original, Cloner cloner)
25      : base(original, cloner) {
26    }
27
28    public override IDeepCloneable Clone(Cloner cloner) {
29      return new TraceCalculator(this, cloner);
30    }
31
32    public static IGenealogyGraph<ISymbolicExpressionTree> TraceSubtree(IGenealogyGraphNode<ISymbolicExpressionTree> node, int subtreeIndex) {
33      var tc = new TraceCalculator();
34      tc.Trace(node, subtreeIndex);
35      return tc.TraceGraph;
36    }
37
38    /// <summary>
39    /// This method starts from a given vertex in the genealogy graph and works its way
40    /// up the ancestry trying to track the structure of the subtree given by subtreeIndex.
41    /// This method will skip genealogy graph nodes that did not have an influence on the
42    /// structure of the tracked subtree.
43    ///
44    /// Only genealogy nodes which did have an influence are added (as copies) to the trace
45    /// and are consequently called 'trace nodes'.
46    ///
47    /// The arcs connecting trace nodes hold information about the locations of the subtrees
48    /// and fragments that have been swapped in the form of a tuple (si, fi, lastSi, lastFi),
49    /// where:
50    /// - si is the subtree index in the current trace node
51    /// - fi is the fragment index in the current trace node
52    /// - lastSi is the subtree index in the previous trace node
53    /// - lastFi is the subtree index in the previous trace node
54    /// </summary>
55    /// <param name="g">The current node in the genealogy graph</param>
56    /// <param name="si">The index of the traced subtree</param>
57    /// <param name="last">The last added node in the trace graph</param>
58    public void Trace(IGenealogyGraphNode<ISymbolicExpressionTree> g, int si, IGenealogyGraphNode<ISymbolicExpressionTree> last = null) {
59      while (g.Parents.Any()) {
60        var parents = g.Parents.ToList();
61        var fragment = (IFragment<ISymbolicExpressionTreeNode>)g.InArcs.Last().Data;
62        if (fragment == null) {
63          // the node is either an elite node or (in rare cases) no fragment was transferred
64          g = parents[0];
65          continue;
66        }
67
68        int fragmentLength = fragment.Root.GetLength();
69        int subtreeLength = g.Data.NodeAt(si).GetLength();
70
71        #region trace crossover
72        if (parents.Count == 2) {
73          if (fragment.Index1 == si) {
74            g = parents[1];
75            si = fragment.Index2;
76            continue;
77          }
78          if (fragment.Index1 < si) {
79            if (fragment.Index1 + fragmentLength > si) {
80              // fragment contains subtree
81              g = parents[1];
82              si += fragment.Index2 - fragment.Index1;
83            } else {
84              // fragment distinct from subtree
85              g = parents[0];
86              si += g.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength;
87            }
88            continue;
89          }
90          if (fragment.Index1 > si) {
91            if (fragment.Index1 < si + subtreeLength) {
92              // subtree contains fragment => branching point in the fragment graph
93              var n = traceGraph.GetByContent(g.Data);
94              if (n == null) {
95                n = g.Copy();
96                traceGraph.AddVertex(n);
97                traceMap[n] = new Tuple<int, int>(si, fragment.Index1);
98              }
99
100              Trace(parents[0], si, n);
101              Trace(parents[1], fragment.Index2, n);
102              break;
103            } else {
104              // subtree and fragment are distinct.
105              g = parents[0];
106              continue;
107            }
108          }
109        }
110        #endregion
111        #region trace mutation
112        if (parents.Count == 1) {
113          if (si == fragment.Index1) {
114            // fragment and subtree coincide
115            // since mutation can potentially alter trees quite drastically, we branch here,
116            // in order not to miss any changes
117            var n = traceGraph.GetByContent(g.Data);
118            if (n == null) {
119              n = g.Copy();
120              traceGraph.AddVertex(n);
121              traceMap[n] = new Tuple<int, int>(si, fragment.Index1);
122            }
123            Trace(parents[0], si, n);
124            break;
125          }
126          if (fragment.Index1 < si) {
127            if (si < fragment.Index1 + fragmentLength) {
128              // fragment contains subtree
129              g = parents[0];
130              si = fragment.Index2;
131            } else {
132              // fragment and subtree are distinct
133              // since the fragment occurs before the subtree in the prefix node ordering
134              // the subtree index must be adjusted according to the fragment length
135              g = parents[0];
136              si += g.Data.NodeAt(fragment.Index1).GetLength() - fragmentLength;
137            }
138            continue;
139          }
140          if (si < fragment.Index1) {
141            // subtree occurs before fragment in the prefix node ordering
142            if (fragment.Index1 < si + subtreeLength) {
143              // subtree contains fragment, we are interested to see what the subtree looked like before
144              // but we also want to keep track of what it looks like now, therefore we branch here
145              var n = traceGraph.GetByContent(g.Data);
146              if (n == null) {
147                n = g.Copy();
148                traceGraph.AddVertex(n);
149                traceMap[n] = new Tuple<int, int>(si, fragment.Index1);
150              }
151              Trace(parents[0], si, n);
152              break;
153            } else {
154              // fragment and subtree are distinct, subtree index stays the same
155              // since the subtree comes before the fragment in the prefix node ordering
156              g = parents[0];
157              continue;
158            }
159          }
160        }
161        #endregion
162        throw new InvalidOperationException("A node cannot have more than two parents");
163      }
164      // when we are out of the while the last vertex must be connected with the current one
165      ConnectLast(g, si, last);
166    }
167
168    /// <summary>
169    /// Connect the current node of the trace graph with the node that was previously added (@last). The current node of the trace graph is determined by the content
170    /// of the genealogy graph node @g. 
171    /// </summary>
172    /// <param name="g">The current node in the genealogy graph</param>
173    /// <param name="si">The index of the traced subtree</param>
174    /// <param name="last">The last added node in the trace graph</param>
175    private void ConnectLast(IGenealogyGraphNode<ISymbolicExpressionTree> g, int si, IGenealogyGraphNode<ISymbolicExpressionTree> last) {
176      IFragment<ISymbolicExpressionTreeNode> fragment = g.Parents.Any() ? (IFragment<ISymbolicExpressionTreeNode>)g.InArcs.Last().Data : null;
177      var n = traceGraph.GetByContent(g.Data);
178      if (n == null) {
179        n = g.Copy();
180        traceGraph.AddVertex(n);
181      }
182      int fi = fragment == null ? 0 : fragment.Index1; // fragment index
183      traceMap[n] = new Tuple<int, int>(si, fi);
184      if (last == null)
185        return;
186      var lastTraceData = traceMap[last];
187      int lastSi = lastTraceData.Item1; // last subtree index
188      int lastFi = lastTraceData.Item2; // last fragment index
189      var td = new Tuple<int, int, int, int>(si, fi, lastSi, lastFi); // trace data
190      var arc = n.InArcs.SingleOrDefault(a => a.Source == last && a.Data.Equals(td));
191      if (arc != null)
192        return;
193      arc = new GenealogyGraphArc(last, n);
194      arc.Data = td;
195      traceGraph.AddArc(arc);
196    }
197  }
198
199  internal static class Util {
200    // shallow node copy (does not clone the data or the arcs)
201    public static IGenealogyGraphNode<ISymbolicExpressionTree> Copy(this IGenealogyGraphNode<ISymbolicExpressionTree> node) {
202      return new GenealogyGraphNode<ISymbolicExpressionTree>(node.Data) { Rank = node.Rank, Quality = node.Quality };
203    }
204    #region some helper methods for shortening the tracing code
205    public static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int index) {
206      return NodeAt(tree.Root, index);
207    }
208    public static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int index) {
209      return root.IterateNodesPrefix().ElementAt(index);
210    }
211    #endregion
212  }
213}
Note: See TracBrowser for help on using the repository browser.