Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Tracking/SymboldDataAnalysisGenealogyView.cs @ 10746

Last change on this file since 10746 was 10746, checked in by bburlacu, 11 years ago

#1772: Small improvements to FragmentGraphView, moved tracking classes to separate folder.

File size: 12.7 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.Drawing;
25using System.IO;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Core.Views;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
31using HeuristicLab.EvolutionTracking;
32using HeuristicLab.EvolutionTracking.Views;
33using HeuristicLab.MainForm;
34
35using FragmentGraph = HeuristicLab.EvolutionTracking.IGenealogyGraph<HeuristicLab.EvolutionTracking.IFragment<HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode>>;
36using FragmentNode = HeuristicLab.EvolutionTracking.GenealogyGraphNode<HeuristicLab.EvolutionTracking.IFragment<HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode>>;
37
38namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
39  [View("SymboldDataAnalysisGenealogyView")]
40  [Content(typeof(IGenealogyGraph<ISymbolicExpressionTree>), IsDefaultView = true)]
41  public partial class SymboldDataAnalysisGenealogyView : ItemView {
42    private readonly ISymbolicExpressionTreeNodeSimilarityComparer comparer;
43
44    public SymboldDataAnalysisGenealogyView() {
45      InitializeComponent();
46
47      comparer = new SymbolicExpressionTreeNodeSimilarityComparer();
48    }
49
50    public new IGenealogyGraph<ISymbolicExpressionTree> Content {
51      get { return (IGenealogyGraph<ISymbolicExpressionTree>)base.Content; }
52      set { base.Content = value; }
53    }
54
55    #region event handlers
56
57    protected override void OnContentChanged() {
58      base.OnContentChanged();
59      if (Content != null) {
60        genealogyGraphChart.GenealogyGraph = Content;
61      }
62    }
63
64    #endregion
65
66    protected override void RegisterContentEvents() {
67      genealogyGraphChart.GenealogyGraphNodeClicked += graphChart_GenealogyGraphNodeClicked;
68      symbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionNodeClicked;
69      base.RegisterContentEvents();
70    }
71
72    protected override void DeregisterContentEvents() {
73      base.DeregisterContentEvents();
74      genealogyGraphChart.GenealogyGraphNodeClicked -= graphChart_GenealogyGraphNodeClicked;
75      symbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionNodeClicked;
76    }
77
78    public void graphChart_GenealogyGraphNodeClicked(object sender, MouseEventArgs args) {
79      var visualNode = (VisualGenealogyGraphNode)sender;
80      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)visualNode.Data;
81      var tree = graphNode.Content;
82      symbolicExpressionTreeChart.Tree = tree;
83
84      if (graphNode.InArcs.Any()) {
85        var fragment = (IFragment<ISymbolicExpressionTreeNode>)graphNode.InArcs.Last().Data;
86        treeChart_HighlightSubtree(fragment.Root);
87      }
88    }
89
90    public void treeChart_SymbolicExpressionNodeClicked(object sender, MouseEventArgs args) {
91      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
92      var subtree = visualNode.Content;
93
94      // highlight the selected subtree inside the displayed tree on the right hand side
95      treeChart_ClearColors();
96      treeChart_HighlightSubtree(subtree);
97
98      bool trace = genealogyGraphChart.TraceFragments; // check whether the mode is 'trace' or 'match'
99
100      if (trace) {
101        // perform fragment tracing
102        var fragmentGraph = TraceSubtree(subtree);
103        MainFormManager.MainForm.ShowContent(fragmentGraph); // display the fragment graph on the screen
104      } else {
105        // perform matching like it was done before
106        // currently there is no possibility to specify the subtree matching criteria
107        var trees = Content.Nodes.Select(x => x.Content);
108        var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(subtree, comparer));
109
110        var matchingVertices = matchingTrees.SelectMany(x => Content[x]).Cast<IGenealogyGraphNode<ISymbolicExpressionTree>>();
111        graphChart_highlightMatchingVertices(matchingVertices);
112      }
113    }
114
115    private void graphChart_highlightMatchingVertices(IEnumerable<IGenealogyGraphNode> vertices) {
116      genealogyGraphChart.Chart.UpdateEnabled = false;
117      genealogyGraphChart.ClearPrimitives();
118      genealogyGraphChart.HighlightNodes(vertices);
119      genealogyGraphChart.Chart.UpdateEnabled = true;
120      genealogyGraphChart.Chart.EnforceUpdate();
121    }
122
123    private void treeChart_ClearColors() {
124      foreach (var node in symbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
125        var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
126        if (visualNode != null) {
127          visualNode.LineColor = Color.Black;
128          visualNode.FillColor = Color.Transparent;
129        }
130      }
131      symbolicExpressionTreeChart.RepaintNodes();
132    }
133
134    private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree) {
135      foreach (var s in subtree.IterateNodesPrefix()) {
136        var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s);
137        visualNode.LineColor = Color.RoyalBlue;
138        visualNode.FillColor = Color.LightBlue;
139
140        foreach (var c in s.Subtrees) {
141          var visualArc = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c);
142          visualArc.LineColor = Color.RoyalBlue;
143        }
144      }
145      symbolicExpressionTreeChart.RepaintNodes();
146    }
147
148    #region events for configuring the behavior of the genealogy chart (trace/match, simple lineages, etc)
149    private void trace_checkBox_CheckedChanged(object sender, System.EventArgs e) {
150      genealogyGraphChart.TraceFragments = trace_checkBox.Checked;
151    }
152
153    private void simpleLineages_checkBox_CheckedChanged(object sender, System.EventArgs e) {
154      genealogyGraphChart.SimpleLineages = simpleLineages_checkBox.Checked;
155    }
156
157    private void lockGraph_checkBox_CheckedChanged(object sender, System.EventArgs e) {
158      genealogyGraphChart.LockGenealogy = lockGraph_checkBox.Checked;
159    }
160    #endregion
161
162    #region fragment tracing
163    private FragmentGraph TraceSubtree(ISymbolicExpressionTreeNode subtree) {
164      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
165      var graph = new GenealogyGraph<IFragment<ISymbolicExpressionTreeNode>>();
166      Trace(graphNode, subtree, graph);
167      return graph;
168    }
169
170    private static void Trace(IGenealogyGraphNode<ISymbolicExpressionTree> graphNode, ISymbolicExpressionTreeNode subtree, FragmentGraph fragmentGraph, FragmentNode parentNode = null) {
171      while (true) {
172        if (!graphNode.InArcs.Any()) return;
173
174        var parentVertices = graphNode.Parents.ToList();
175        // the subtree must belong to the currently displayed tree which in turn must belong to the currently selected graph node
176        var tree = graphNode.Content;
177        var subtreeIndex = tree.IndexOf(subtree);
178        var subtreeLength = subtree.GetLength();
179
180        var fragment = (IFragment<ISymbolicExpressionTreeNode>)graphNode.InArcs.Last().Data;
181        if (fragment == null) return;
182        var fragmentLength = fragment.Root.GetLength();
183
184        var fragmentNode = new FragmentNode {
185          Content = new Fragment<ISymbolicExpressionTreeNode> {
186            Root = subtree,
187          },
188          Rank = graphNode.Rank
189        };
190
191        if (parentNode != null) {
192          if (parentNode == fragmentNode) {
193            throw new Exception("Node cannot be a child of itself!");
194          }
195          var arc = new GenealogyGraphArc { Source = parentNode, Target = fragmentNode };
196          parentNode.AddForwardArc(arc);
197        }
198        fragmentGraph.AddVertex(fragmentNode);
199
200        parentNode = fragmentNode;
201
202        // if the selected subtree is the actual fragment
203        if (fragment.Index == subtreeIndex) {
204          if (fragmentLength != subtreeLength) throw new Exception("Fragment and subtree lengths should be the same!");
205          graphNode = parentVertices.Last();
206          tree = graphNode.Content;
207          subtree = tree.NodeAt(fragment.OldIndex);
208          continue;
209        }
210        // if the fragment contains the selected subtree => track fragment, then track subtree
211        if (fragment.Index < subtreeIndex && subtreeIndex < fragment.Index + fragmentLength) {
212          if (subtreeLength >= fragmentLength) throw new Exception("Fragment contains subtree, so subtree length should be less than the fragment length.");
213
214          graphNode = parentVertices.Last();
215          tree = graphNode.Content;
216          var i = fragment.Root.IndexOf(subtree); // get the index of the selected subtree, relative to the fragment root
217          subtree = tree.NodeAt(fragment.OldIndex + i);
218          continue;
219        }
220        // if the selected subtree contains the fragment => track fragment and subtree
221        if (subtreeIndex < fragment.Index && fragment.Index < subtreeIndex + subtreeLength) {
222          if (fragmentLength >= subtreeLength) throw new Exception("Subtree contains fragment, so fragment length should be less than the subtree length.");
223          fragmentNode.Content.Index = fragment.Index - subtreeIndex;
224          graphNode = parentVertices[0];
225          // debug check
226          tree = graphNode.Content;
227          subtree = tree.NodeAt(subtreeIndex);
228          if (subtree.GetLength() <= fragmentNode.Content.Index) {
229            throw new Exception("Index exceeds subtree length.");
230          }
231          // track subtree
232          Trace(graphNode, subtree, fragmentGraph, fragmentNode);
233
234          // track fragment
235          if (parentVertices.Count > 1) {
236            // save the index of the current fragment in the tree where it was swapped
237            graphNode = parentVertices[1];
238            tree = graphNode.Content;
239            subtree = tree.NodeAt(fragment.OldIndex);
240            continue;
241          }
242        } else {
243          // fragment and subtree are completely distinct => we only track the subtree (contained by the root parent)
244          // if the subtree comes AFTER the fragment in the prefix iteration of nodes,
245          // then its index is affected by the difference in fragment size between current tree and parent
246          graphNode = parentVertices[0];
247          tree = graphNode.Content;
248          if (subtreeIndex > fragment.Index) {
249            var diff = tree.NodeAt(fragment.Index).GetLength() - fragmentLength;
250            subtreeIndex += diff;
251          }
252          subtree = tree.NodeAt(subtreeIndex);
253          continue;
254        }
255        break;
256      }
257    }
258    #endregion
259  }
260
261  internal static class Util {
262    private static string ViewAsText(this ISymbolicExpressionTreeNode root) {
263      var writer = new StringWriter();
264      SymbolicExpressionTreeHierarchicalFormatter.RenderNode(writer, root, string.Empty);
265      return writer.ToString();
266    }
267    #region some helper methods for shortening the tracing code
268
269    internal static void AddChild(this IGenealogyGraphNode parent, IGenealogyGraphNode child) {
270      parent.AddForwardArc(child);
271      child.AddReverseArc(parent);
272      child.Rank = parent.Rank - 1;
273    }
274    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
275      return NodeAt(tree.Root, position);
276    }
277    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
278      return root.IterateNodesPrefix().ElementAt(position);
279    }
280    internal static int IndexOf(this ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode node) {
281      return IndexOf(tree.Root, node);
282    }
283    internal static int IndexOf(this ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node) {
284      int i = 0;
285      foreach (var n in root.IterateNodesPrefix()) {
286        if (n == node) return i;
287        ++i;
288      }
289      return -1;
290    }
291    #endregion
292  }
293}
Note: See TracBrowser for help on using the repository browser.