Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Tracking/SymbolicDataAnalysisGenealogyGraphView.cs @ 12225

Last change on this file since 12225 was 12225, checked in by bburlacu, 8 years ago

#1772: Work in progress for calculating sampling counts for subtrees in the population: updated TraceCalculator to aggregate tracing statistics, updated SymbolicDataAnalysisGenealogyGraphView, added SymbolicDataAnalysisSubtreeSampleCountAnalyzer.

File size: 14.5 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.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
31using HeuristicLab.EvolutionTracking;
32using HeuristicLab.EvolutionTracking.Views;
33using HeuristicLab.MainForm;
34
35namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
36  [View("SymbolicDataAnalysisGenealogyGraphView")]
37  [Content(typeof(IGenealogyGraph<ISymbolicExpressionTree>), IsDefaultView = true)]
38  public partial class SymbolicDataAnalysisGenealogyGraphView : SymbolicDataAnalysisGenealogyGraphViewDesignable {
39    private readonly ISymbolicExpressionTreeNodeEqualityComparer comparer;
40
41    private ISymbolicExpressionTreeNode selectedSubtree;
42    private ISymbolicExpressionTreeNode SelectedSubtree {
43      get { return selectedSubtree; }
44      set {
45        if (value == null || selectedSubtree == value) return;
46        selectedSubtree = value;
47        ClonedSubtree = (ISymbolicExpressionTreeNode)selectedSubtree.Clone();
48      }
49    }
50    // the clone is necessary in order to deselect parts of a tree (by removing subtrees)
51    // and do "high level" matching of the remaining part
52    private ISymbolicExpressionTreeNode ClonedSubtree { get; set; }
53
54    // we use the symbolic expression tree chart to call the drawing routines
55    // and highlight relevant tree parts
56    public SymbolicExpressionTreeChart SymbolicExpressionTreeChart {
57      get {
58        var view = (GraphicalSymbolicExpressionTreeView)base.viewHost.ActiveView;
59        return view == null ? null : view.SymbolicExpressionTreeChart;
60      }
61    }
62
63    public SymbolicDataAnalysisGenealogyGraphView() {
64      InitializeComponent();
65      comparer = new SymbolicExpressionTreeNodeEqualityComparer();
66      viewHost.ViewType = typeof(GraphicalSymbolicExpressionTreeView);
67    }
68    #region event handlers
69    protected override void OnContentChanged() {
70      base.OnContentChanged();
71      if (Content != null && Content != genealogyGraphChart.GenealogyGraph) {
72        genealogyGraphChart.GenealogyGraph = Content;
73      }
74    }
75
76    public override void graphChart_GenealogyGraphNodeClicked(object sender, MouseEventArgs args) {
77      base.graphChart_GenealogyGraphNodeClicked(sender, args);
78      var visualNode = (VisualGenealogyGraphNode)sender;
79      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)visualNode.Data;
80
81      nodeQualityLabel.Text = String.Format("{0:0.000}", graphNode.Quality);
82      nodeRankLabel.Text = String.Format("{0:0.0}", graphNode.Rank);
83      nodeDegreeLabel.Text = String.Format("{0} / {1}", graphNode.InDegree, graphNode.OutDegree);
84      nodeWeightLabel.Text = String.Format("{0:0.00}", graphNode.Weight);
85
86      if (openNew_CheckBox.Checked) {
87        // get the ancestors into a new view
88        var cloner = new Cloner();
89        // clone arcs and vertices and use them to create a new graph
90        // that will include just the individual and its ancestors
91        var graph = new GenealogyGraph<ISymbolicExpressionTree>();
92        var ancestors = new[] { graphNode }.Concat(graphNode.Ancestors).ToList();
93        graph.AddVertices(ancestors.Select(cloner.Clone));
94        graph.AddArcs(ancestors.SelectMany(x => x.InArcs).Select(cloner.Clone));
95        MainFormManager.MainForm.ShowContent(graph);
96      }
97
98      if (graphNode.InArcs.Any()) {
99        var data = graphNode.InArcs.Last().Data;
100        var fragment = data as IFragment<ISymbolicExpressionTreeNode>;
101        var td = data as TraceData;
102        //        double max = Content.Vertices.SelectMany(x => x.Data.IterateNodesPrefix()).Max(x => x.NodeWeight);
103
104        if (fragment != null) {
105          //          treeChart_HighlightSubtree(graphNode.Data.NodeAt(fragment.Index1));
106          var nodes = graphNode.Data.IterateNodesPrefix().ToList();
107          int c = ColorGradient.Colors.Count - 1;
108          foreach (var n in nodes.Skip(1)) { // skip program root symbol
109            //            var i = (int)Math.Round(n.NodeWeight / max * c);
110            //            const int alpha = 50;
111            //            var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
112
113            //            treeChart_HighlightSubtree(n, null, fillColor);
114          }
115        } else if (td != null) {
116
117          var nodes = graphNode.Data.IterateNodesPrefix().ToList();
118          int c = ColorGradient.Colors.Count - 1;
119          foreach (var n in nodes.Skip(1)) { // skip program root symbol
120            //            var i = (int)Math.Round(n.NodeWeight / max * c);
121            //            const int alpha = 50;
122            //            var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
123
124            //            treeChart_HighlightSubtree(n, null, fillColor);
125          }
126
127          treeChart_HighlightSubtree(nodes[td.LastSubtreeIndex], Color.Orange);
128          treeChart_HighlightSubtree(nodes[td.LastFragmentIndex], Color.CornflowerBlue);
129        }
130      }
131    }
132
133    public void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs args) {
134      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
135      var subtree = visualNode.Content;
136      // highlight the selected subtree inside the displayed tree on the right hand side
137      treeChart_ClearColors();
138      treeChart_HighlightSubtree(subtree, Color.Black, Color.RoyalBlue);
139
140      bool trace = genealogyGraphChart.TraceFragments; // check whether we are in 'trace' or 'match' mode
141
142      switch (args.Button) {
143        case MouseButtons.Left:
144          SelectedSubtree = subtree;
145          if (trace) {
146            // perform fragment tracing
147            var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
148            var subtreeIndex = graphNode.Data.IterateNodesPrefix().ToList().IndexOf(subtree);
149            var traceGraph = TraceCalculator.TraceSubtree(graphNode, subtreeIndex, updateVertexWeights: true, updateSubtreeWeights: true, cacheTraceNodes: true);
150            if (traceGraph.Vertices.Any()) {
151              genealogyGraphChart.UpdateEnabled = false;
152              genealogyGraphChart.ClearPrimitives();
153              var traceVertices = traceGraph.Vertices.ToList();
154              var genealogyNodes = traceVertices.Select(v => Content.GetByContent(v.Data)).ToList();
155              // color graph vertices according to their weight
156              double max = traceGraph.Vertices.Max(x => x.Data.IterateNodesPrefix().Max(n => x.Weight));
157              for (int i = 0; i < genealogyNodes.Count; ++i) {
158                var g = genealogyNodes[i];
159                g.Weight = traceVertices[i].Weight;
160                var v = genealogyGraphChart.GetMappedNode(g);
161                if (v != null) {
162                  v.Brush = new SolidBrush(ColorGradient.Colors[(int)Math.Round(g.Weight * (ColorGradient.Colors.Count - 1) / max)]);
163                }
164              }
165
166              genealogyGraphChart.UpdateEnabled = true;
167              genealogyGraphChart.EnforceUpdate();
168
169              if (openNew_CheckBox.Checked)
170                MainFormManager.MainForm.ShowContent(traceGraph); // display the fragment graph on the screen
171            }
172          } else {
173            // perform matching like it was done before
174            // currently there is no possibility to specify the subtree matching criteria
175            var trees = Content.Vertices.Select(x => x.Data);
176            var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(subtree, comparer));
177
178            var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
179            graphChart_HighlightMatchingVertices(matchingVertices);
180          }
181          break;
182        case MouseButtons.Middle:
183          var index = SelectedSubtree.IterateNodesPrefix().ToList().IndexOf(subtree);
184          if (index > 0) {
185            var s = ClonedSubtree.NodeAt(index);
186            s.Parent.RemoveSubtree(s.Parent.IndexOfSubtree(s));
187
188            var trees = Content.Vertices.Select(x => x.Data);
189            var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(ClonedSubtree, comparer));
190
191            var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
192            treeChart_HighlightSubtree(subtree, Color.Black, Color.White);
193            graphChart_HighlightMatchingVertices(matchingVertices);
194          }
195          break;
196      }
197    }
198    #endregion
199
200    protected override void RegisterContentEvents() {
201      base.RegisterContentEvents();
202      if (SymbolicExpressionTreeChart != null)
203        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked;
204    }
205
206    protected override void DeregisterContentEvents() {
207      if (SymbolicExpressionTreeChart != null)
208        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked;
209      base.DeregisterContentEvents();
210    }
211
212    private void graphChart_HighlightMatchingVertices(IEnumerable<IGenealogyGraphNode> vertices) {
213      genealogyGraphChart.Chart.UpdateEnabled = false;
214      genealogyGraphChart.ClearPrimitives();
215      genealogyGraphChart.HighlightNodes(vertices);
216      genealogyGraphChart.Chart.UpdateEnabled = true;
217      genealogyGraphChart.Chart.EnforceUpdate();
218    }
219
220    private void treeChart_ClearColors() {
221      foreach (var node in SymbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
222        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
223        if (visualNode != null) {
224          visualNode.LineColor = Color.Black;
225          visualNode.FillColor = Color.Transparent;
226        }
227      }
228      SymbolicExpressionTreeChart.RepaintNodes();
229    }
230
231    private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree, Color? lineColor = null, Color? fillColor = null) {
232      if (lineColor == null && fillColor == null)
233        return;
234
235      foreach (var s in subtree.IterateNodesPrefix()) {
236        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s);
237        if (lineColor != null) {
238          visualNode.LineColor = (Color)lineColor;
239          foreach (var c in s.Subtrees) {
240            var visualArc = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c);
241            visualArc.LineColor = (Color)lineColor;
242          }
243        }
244        if (fillColor != null)
245          visualNode.FillColor = (Color)fillColor;
246      }
247      SymbolicExpressionTreeChart.RepaintNodes();
248    }
249
250    #region navigate the genealogy / trace graph
251    private void navigateLeftButton_Click(object sender, EventArgs e) {
252      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
253      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
254      if (inArcs.Count > 0) {
255        genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
256      }
257    }
258
259    private void navigateRightButton_Click(object sender, EventArgs e) {
260      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
261      var inArcs = graphNode.InArcs.ToList();
262      if (inArcs.Count > 0) {
263        var data = inArcs.Last().Data;
264        var fragment = (data as IFragment<ISymbolicExpressionTreeNode>);
265        var td = data as TraceData;
266        if (fragment != null) {
267          genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs.Last().Source;
268        } else if (td != null) {
269          if (inArcs.Count == 1) {
270            genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
271            return;
272          }
273          // the first arc from inArcs will always represent the connection to the root parent
274          // (tracing the body of the traced subtree)
275          // therefore, in order to follow the correct non-root parent, we have to find the correct arc
276          // But, the FragmentIndex recorded in the TraceData of the first arc has to match the SubtreeIndex recorded in the TraceData of the searched arc
277          td = (TraceData)inArcs[0].Data;
278          var f1 = (graphNode.Data).NodeAt(td.LastFragmentIndex);
279          for (int i = 1; i < inArcs.Count; ++i) {
280            td = (TraceData)inArcs[i].Data;
281            var f2 = ((IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[i].Source).Data.NodeAt(td.SubtreeIndex);
282            // if the subtrees are the same we have found a match
283            // note: this is not necessarily 100% correct if in the trace graph we have identical fragments on different arcs
284            if (f1.Difference(f2) == null) {
285              genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[i].Source;
286              return;
287            }
288          }
289          throw new InvalidOperationException("Error calculating the next step.");
290        }
291      }
292    }
293    #endregion
294  }
295
296  // bogus class needed in order to be able to "design" the view
297  public class SymbolicDataAnalysisGenealogyGraphViewDesignable : GenealogyGraphView<ISymbolicExpressionTree> { }
298
299  #region helper methods
300  internal static class Util {
301    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
302      return NodeAt(tree.Root, position);
303    }
304    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
305      return root.IterateNodesPrefix().ElementAt(position);
306    }
307  }
308  #endregion
309}
Note: See TracBrowser for help on using the repository browser.