Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 12265 was 12265, checked in by bburlacu, 9 years ago

#1772: Some more work on subtree sample counting.

File size: 14.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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 (!graphNode.InArcs.Any()) return;
87
88      if (openNew_CheckBox.Checked) {
89        // get the ancestors into a new view
90        var cloner = new Cloner();
91        // clone arcs and vertices and use them to create a new graph
92        // that will include just the individual and its ancestors
93        var graph = new GenealogyGraph<ISymbolicExpressionTree>();
94        var ancestors = new[] { graphNode }.Concat(graphNode.Ancestors).ToList();
95        graph.AddVertices(ancestors.Select(cloner.Clone));
96        graph.AddArcs(ancestors.SelectMany(x => x.InArcs).Select(cloner.Clone));
97        MainFormManager.MainForm.ShowContent(graph);
98      }
99
100      var data = graphNode.InArcs.Last().Data;
101      var fragment = data as IFragment<ISymbolicExpressionTreeNode>;
102      var td = data as TraceData;
103      // calculate max only in the current generation
104      var max = Content.GetByRank(graphNode.Rank).Max(x => ((IGenealogyGraphNode<ISymbolicExpressionTree>)x).Data.IterateNodesPrefix().Max(y => y.NodeWeight));
105      //      var max = Content.GetByRank(graphNode.Rank).Max(x => x.Weight);
106
107      if (max.IsAlmost(0))
108        max = 1;
109
110      int colorCount = ColorGradient.Colors.Count - 1;
111      const int alpha = 100;
112      if (fragment != null) {
113        // highlight the fragment with a blue line color
114        foreach (var n in graphNode.Data.NodeAt(fragment.Index1).IterateNodesPrefix()) {
115          treeChart_HighlightSubtree(n, Color.CornflowerBlue);
116        }
117        // highlight all the nodes according to their sample count
118        var nodes = graphNode.Data.IterateNodesPrefix().ToList();
119        foreach (var n in nodes.Skip(1)) {
120          var i = (int)Math.Round(n.NodeWeight / max * colorCount);
121          var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
122          treeChart_HighlightSubtree(n, null, fillColor);
123        }
124      } else if (td != null) {
125        var nodes = graphNode.Data.IterateNodesPrefix().ToList();
126        foreach (var n in nodes.Skip(1)) { // skip program root symbol
127          var i = (int)Math.Round(n.NodeWeight / max * colorCount);
128          var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
129          treeChart_HighlightSubtree(n, null, fillColor);
130        }
131        treeChart_HighlightSubtree(nodes[td.LastSubtreeIndex], Color.Orange);
132        treeChart_HighlightSubtree(nodes[td.LastFragmentIndex], Color.CornflowerBlue);
133      }
134    }
135
136    #region specific symbolic expression tree node click actions
137    private void OnTreeNodeLeftClicked(ISymbolicExpressionTreeNode node) {
138      SelectedSubtree = node;
139      bool trace = genealogyGraphChart.TraceFragments;
140
141      // check whether we are in 'trace' or 'match' mode
142      if (trace) {
143        // TODO: maybe highlight based on per generation maximum
144        //        double max = Content.Vertices.Max(x => x.Data.IterateNodesPrefix().Average(y => y.NodeWeight));
145        // perform fragment tracing
146        var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
147        var max = Content.GetByRank(graphNode.Rank).Max(x => x.Weight);
148        var subtreeIndex = graphNode.Data.IterateNodesPrefix().ToList().IndexOf(node);
149        var traceGraph = TraceCalculator.TraceSubtree(graphNode, subtreeIndex, updateVertexWeights: false, updateSubtreeWeights: false, cacheTraceNodes: true);
150        if (traceGraph.Vertices.Any()) {
151          var vertices = traceGraph.Vertices.Select(x => Content.GetByContent(x.Data));
152          genealogyGraphChart.UpdateEnabled = false;
153          genealogyGraphChart.ClearPrimitives();
154          foreach (var v in vertices) {
155            var vNode = genealogyGraphChart.GetMappedNode(v);
156            var wSum = v.Data.IterateNodesPrefix().Average(x => x.NodeWeight);
157            // use a grayscale gradient
158            var color = ColorGradient.GrayscaledColors[(int)Math.Round(wSum / max * (ColorGradient.GrayscaledColors.Count - 1))];
159            vNode.Brush = new SolidBrush(color);
160          }
161          genealogyGraphChart.UpdateEnabled = true;
162          genealogyGraphChart.EnforceUpdate();
163
164          if (openNew_CheckBox.Checked) {
165            MainFormManager.MainForm.ShowContent(traceGraph); // display the fragment graph on the screen
166          }
167        }
168      } else {
169        // perform matching like it was done before
170        // currently there is no possibility to specify the subtree matching criteria
171        var trees = Content.Vertices.Select(x => x.Data);
172        var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(node, comparer));
173
174        var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
175        graphChart_HighlightMatchingVertices(matchingVertices);
176      }
177    }
178
179    private void OnTreeNodeMiddleClicked(ISymbolicExpressionTreeNode node) {
180      var index = SelectedSubtree.IterateNodesPrefix().ToList().IndexOf(node);
181      if (index > 0) {
182        var s = ClonedSubtree.NodeAt(index);
183        s.Parent.RemoveSubtree(s.Parent.IndexOfSubtree(s));
184
185        var trees = Content.Vertices.Select(x => x.Data);
186        var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(ClonedSubtree, comparer));
187
188        var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
189        treeChart_HighlightSubtree(node, Color.Black, Color.White);
190        graphChart_HighlightMatchingVertices(matchingVertices);
191      }
192    }
193    #endregion
194
195    public void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs args) {
196      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
197      var subtree = visualNode.Content;
198      // highlight the selected subtree inside the displayed tree on the right hand side
199      treeChart_ClearColors();
200      treeChart_HighlightSubtree(subtree, Color.Black, Color.RoyalBlue);
201
202      switch (args.Button) {
203        case MouseButtons.Left: {
204            OnTreeNodeLeftClicked(subtree);
205            break;
206          }
207        case MouseButtons.Middle: {
208            OnTreeNodeMiddleClicked(subtree);
209            break;
210          }
211      }
212    }
213    #endregion
214
215    protected override void RegisterContentEvents() {
216      base.RegisterContentEvents();
217      if (SymbolicExpressionTreeChart != null)
218        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked;
219    }
220
221    protected override void DeregisterContentEvents() {
222      if (SymbolicExpressionTreeChart != null)
223        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked;
224      base.DeregisterContentEvents();
225    }
226
227    private void graphChart_HighlightMatchingVertices(IEnumerable<IGenealogyGraphNode> vertices) {
228      genealogyGraphChart.Chart.UpdateEnabled = false;
229      genealogyGraphChart.ClearPrimitives();
230      genealogyGraphChart.HighlightNodes(vertices);
231      genealogyGraphChart.Chart.UpdateEnabled = true;
232      genealogyGraphChart.Chart.EnforceUpdate();
233    }
234
235    private void treeChart_ClearColors() {
236      foreach (var node in SymbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
237        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
238        if (visualNode != null) {
239          visualNode.LineColor = Color.Black;
240          visualNode.FillColor = Color.Transparent;
241        }
242      }
243      SymbolicExpressionTreeChart.RepaintNodes();
244    }
245
246    private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree, Color? lineColor = null, Color? fillColor = null) {
247      if (lineColor == null && fillColor == null)
248        return;
249
250      foreach (var s in subtree.IterateNodesPrefix()) {
251        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s);
252        if (lineColor != null) {
253          visualNode.LineColor = (Color)lineColor;
254          foreach (var c in s.Subtrees) {
255            var visualArc = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c);
256            visualArc.LineColor = (Color)lineColor;
257          }
258        }
259        if (fillColor != null)
260          visualNode.FillColor = (Color)fillColor;
261      }
262      SymbolicExpressionTreeChart.RepaintNodes();
263    }
264
265    #region navigate the genealogy / trace graph
266    private void navigateLeftButton_Click(object sender, EventArgs e) {
267      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
268      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
269      if (inArcs.Count > 0) {
270        genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
271      }
272    }
273
274    private void navigateRightButton_Click(object sender, EventArgs e) {
275      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
276      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
277      if (inArcs.Count > 0) {
278        if (inArcs.Count == 1) {
279          genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
280          return;
281        }
282        IGenealogyGraphNode<ISymbolicExpressionTree> source = null;
283        var fragment = ((IArc<IDeepCloneable>)inArcs.Last()).Data as IFragment<ISymbolicExpressionTreeNode>;
284        var traceData = ((IArc<IDeepCloneable>)inArcs[0]).Data as TraceData;
285        if (fragment != null) {
286          source = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs.Last().Source;
287        }
288        if (traceData != null) {
289          var f = graphNode.Data.NodeAt(traceData.LastFragmentIndex);
290          var selected = inArcs.Skip(1).First(x => {
291            var td = (TraceData)((IArc<IDeepCloneable>)x).Data;
292            var s = (IGenealogyGraphNode<ISymbolicExpressionTree>)x.Source;
293            return f.Difference(s.Data.NodeAt(td.SubtreeIndex)) == null;
294          });
295          source = (IGenealogyGraphNode<ISymbolicExpressionTree>)selected.Source;
296        }
297        if (source != null)
298          genealogyGraphChart.SelectedGraphNode = source;
299      }
300    }
301    #endregion
302  }
303
304  // bogus class needed in order to be able to "design" the view
305  public class SymbolicDataAnalysisGenealogyGraphViewDesignable : GenealogyGraphView<ISymbolicExpressionTree> { }
306
307  #region helper methods
308  internal static class Util {
309    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
310      return NodeAt(tree.Root, position);
311    }
312    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
313      return root.IterateNodesPrefix().ElementAt(position);
314    }
315  }
316  #endregion
317}
Note: See TracBrowser for help on using the repository browser.