Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1772: Changed the way node highlighting is performed (taking into account sampling count relative to current generation). Made NodeWeight field storable in the SymbolicExpressionTreeNode. Updated the statistics counting in the TraceCalculator.

File size: 14.8 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.Max(x => x.Data.IterateNodesPrefix().Max(y => y.NodeWeight));
103
104        // calculate max only in the current generation
105        double max = Content.GetByRank(graphNode.Rank).Max(x => ((IGenealogyGraphNode<ISymbolicExpressionTree>)x).Data.IterateNodesPrefix().Max(y => y.NodeWeight));
106        if (max.IsAlmost(0)) max = 1;
107        int c = ColorGradient.Colors.Count - 1;
108        const int alpha = 100;
109        if (fragment != null) {
110          // highlight the fragment with a blue line color
111          foreach (var n in graphNode.Data.NodeAt(fragment.Index1).IterateNodesPrefix()) {
112            treeChart_HighlightSubtree(n, Color.CornflowerBlue);
113          }
114          // highlight all the nodes according to their sample count
115          var nodes = graphNode.Data.IterateNodesPrefix().ToList();
116          foreach (var n in nodes.Skip(1)) {
117            var i = (int)Math.Round(n.NodeWeight / max * c);
118            var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
119            treeChart_HighlightSubtree(n, null, fillColor);
120          }
121        } else if (td != null) {
122          var nodes = graphNode.Data.IterateNodesPrefix().ToList();
123          foreach (var n in nodes.Skip(1)) { // skip program root symbol
124            var i = (int)Math.Round(n.NodeWeight / max * c);
125            var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
126            treeChart_HighlightSubtree(n, null, fillColor);
127          }
128          treeChart_HighlightSubtree(nodes[td.LastSubtreeIndex], Color.Orange);
129          treeChart_HighlightSubtree(nodes[td.LastFragmentIndex], Color.CornflowerBlue);
130        }
131      }
132    }
133
134    public void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs args) {
135      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
136      var subtree = visualNode.Content;
137      // highlight the selected subtree inside the displayed tree on the right hand side
138      treeChart_ClearColors();
139      treeChart_HighlightSubtree(subtree, Color.Black, Color.RoyalBlue);
140
141      bool trace = genealogyGraphChart.TraceFragments; // check whether we are in 'trace' or 'match' mode
142
143      switch (args.Button) {
144        case MouseButtons.Left: {
145            SelectedSubtree = subtree;
146            if (trace) {
147              // TODO: maybe highlight based on per generation maximum
148              double max = Content.Vertices.Max(x => x.Data.IterateNodesPrefix().Average(y => y.NodeWeight));
149              // perform fragment tracing
150              var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
151              var subtreeIndex = graphNode.Data.IterateNodesPrefix().ToList().IndexOf(subtree);
152              var traceGraph = TraceCalculator.TraceSubtree(graphNode, subtreeIndex, updateVertexWeights: false, updateSubtreeWeights: false, cacheTraceNodes: true);
153              if (traceGraph.Vertices.Any()) {
154                var vertices = traceGraph.Vertices.Select(x => Content.GetByContent(x.Data));
155                genealogyGraphChart.UpdateEnabled = false;
156                genealogyGraphChart.ClearPrimitives();
157                foreach (var v in vertices) {
158                  var vNode = genealogyGraphChart.GetMappedNode(v);
159                  var wSum = v.Data.IterateNodesPrefix().Average(x => x.NodeWeight);
160                  // use a grayscal gradient
161                  var color = ColorGradient.GrayscaledColors[(int)Math.Round(wSum / max * (ColorGradient.GrayscaledColors.Count - 1))];
162                  vNode.Brush = new SolidBrush(color);
163                }
164                genealogyGraphChart.UpdateEnabled = true;
165                genealogyGraphChart.EnforceUpdate();
166
167                if (openNew_CheckBox.Checked) {
168                  MainFormManager.MainForm.ShowContent(traceGraph); // display the fragment graph on the screen
169                }
170              }
171            } else {
172              // perform matching like it was done before
173              // currently there is no possibility to specify the subtree matching criteria
174              var trees = Content.Vertices.Select(x => x.Data);
175              var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(subtree, comparer));
176
177              var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
178              graphChart_HighlightMatchingVertices(matchingVertices);
179            }
180            break;
181          }
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    }
199    #endregion
200
201    protected override void RegisterContentEvents() {
202      base.RegisterContentEvents();
203      if (SymbolicExpressionTreeChart != null)
204        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked;
205    }
206
207    protected override void DeregisterContentEvents() {
208      if (SymbolicExpressionTreeChart != null)
209        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked;
210      base.DeregisterContentEvents();
211    }
212
213    private void graphChart_HighlightMatchingVertices(IEnumerable<IGenealogyGraphNode> vertices) {
214      genealogyGraphChart.Chart.UpdateEnabled = false;
215      genealogyGraphChart.ClearPrimitives();
216      genealogyGraphChart.HighlightNodes(vertices);
217      genealogyGraphChart.Chart.UpdateEnabled = true;
218      genealogyGraphChart.Chart.EnforceUpdate();
219    }
220
221    private void treeChart_ClearColors() {
222      foreach (var node in SymbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
223        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
224        if (visualNode != null) {
225          visualNode.LineColor = Color.Black;
226          visualNode.FillColor = Color.Transparent;
227        }
228      }
229      SymbolicExpressionTreeChart.RepaintNodes();
230    }
231
232    private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree, Color? lineColor = null, Color? fillColor = null) {
233      if (lineColor == null && fillColor == null)
234        return;
235
236      foreach (var s in subtree.IterateNodesPrefix()) {
237        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s);
238        if (lineColor != null) {
239          visualNode.LineColor = (Color)lineColor;
240          foreach (var c in s.Subtrees) {
241            var visualArc = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c);
242            visualArc.LineColor = (Color)lineColor;
243          }
244        }
245        if (fillColor != null)
246          visualNode.FillColor = (Color)fillColor;
247      }
248      SymbolicExpressionTreeChart.RepaintNodes();
249    }
250
251    #region navigate the genealogy / trace graph
252    private void navigateLeftButton_Click(object sender, EventArgs e) {
253      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
254      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
255      if (inArcs.Count > 0) {
256        genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
257      }
258    }
259
260    private void navigateRightButton_Click(object sender, EventArgs e) {
261      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
262      var inArcs = graphNode.InArcs.ToList();
263      if (inArcs.Count > 0) {
264        var data = inArcs.Last().Data;
265        var fragment = (data as IFragment<ISymbolicExpressionTreeNode>);
266        var td = data as TraceData;
267        if (fragment != null) {
268          genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs.Last().Source;
269        } else if (td != null) {
270          if (inArcs.Count == 1) {
271            genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
272            return;
273          }
274          // the first arc from inArcs will always represent the connection to the root parent
275          // (tracing the body of the traced subtree)
276          // therefore, in order to follow the correct non-root parent, we have to find the correct arc
277          // But, the FragmentIndex recorded in the TraceData of the first arc has to match the SubtreeIndex recorded in the TraceData of the searched arc
278          td = (TraceData)inArcs[0].Data;
279          var f1 = (graphNode.Data).NodeAt(td.LastFragmentIndex);
280          for (int i = 1; i < inArcs.Count; ++i) {
281            td = (TraceData)inArcs[i].Data;
282            var f2 = ((IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[i].Source).Data.NodeAt(td.SubtreeIndex);
283            // if the subtrees are the same we have found a match
284            // note: this is not necessarily 100% correct if in the trace graph we have identical fragments on different arcs
285            if (f1.Difference(f2) == null) {
286              genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[i].Source;
287              return;
288            }
289          }
290          throw new InvalidOperationException("Error calculating the next step.");
291        }
292      }
293    }
294    #endregion
295  }
296
297  // bogus class needed in order to be able to "design" the view
298  public class SymbolicDataAnalysisGenealogyGraphViewDesignable : GenealogyGraphView<ISymbolicExpressionTree> { }
299
300  #region helper methods
301  internal static class Util {
302    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
303      return NodeAt(tree.Root, position);
304    }
305    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
306      return root.IterateNodesPrefix().ElementAt(position);
307    }
308  }
309  #endregion
310}
Note: See TracBrowser for help on using the repository browser.