Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1772: Updated genealogy graph view and worked on subtree sample count.

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