#region License Information /* HeuristicLab * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views; using HeuristicLab.EvolutionTracking; using HeuristicLab.EvolutionTracking.Views; using HeuristicLab.MainForm; namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views { [View("SymbolicDataAnalysisGenealogyGraphView")] [Content(typeof(IGenealogyGraph), IsDefaultView = true)] public partial class SymbolicDataAnalysisGenealogyGraphView : SymbolicDataAnalysisGenealogyGraphViewDesignable { private readonly ISymbolicExpressionTreeNodeSimilarityComparer comparer; public SymbolicDataAnalysisGenealogyGraphView() { InitializeComponent(); comparer = new SymbolicExpressionTreeNodeSimilarityComparer(); viewHost.ViewType = typeof(GraphicalSymbolicExpressionTreeView); } #region event handlers protected override void OnContentChanged() { base.OnContentChanged(); if (Content != null) { genealogyGraphChart.GenealogyGraph = Content; } } #endregion public SymbolicExpressionTreeChart SymbolicExpressionTreeChart { get { var view = (GraphicalSymbolicExpressionTreeView)base.viewHost.ActiveView; return view == null ? null : view.SymbolicExpressionTreeChart; } } protected override void RegisterContentEvents() { base.RegisterContentEvents(); if (SymbolicExpressionTreeChart != null) SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked; } protected override void DeregisterContentEvents() { if (SymbolicExpressionTreeChart != null) SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked; base.DeregisterContentEvents(); } public override void graphChart_GenealogyGraphNodeClicked(object sender, MouseEventArgs args) { base.graphChart_GenealogyGraphNodeClicked(sender, args); var visualNode = (VisualGenealogyGraphNode)sender; var graphNode = (IGenealogyGraphNode)visualNode.Data; nodeQualityLabel.Text = String.Format("{0:0.000}", graphNode.Quality); nodeRankLabel.Text = String.Format("{0:0.0}", graphNode.Rank); nodeDegreeLabel.Text = String.Format("{0} / {1}", graphNode.InDegree, graphNode.OutDegree); if (openNew_CheckBox.Checked) { // get the ancestors into a new view var cloner = new Cloner(); // clone arcs and vertices and use them to create a new graph // that will include just the individual and its ancestors var graph = new GenealogyGraph(); var ancestors = new[] { graphNode }.Concat(graphNode.Ancestors); var cloned = ancestors.ToDictionary(x => x, x => cloner.Clone(x)); graph.AddVertices(cloned.Values); foreach (var arc in cloned.Keys.SelectMany(x => x.InArcs)) { graph.AddArc(cloner.Clone(arc)); } MainFormManager.MainForm.ShowContent(graph); } if (graphNode.InArcs.Any()) { var data = graphNode.InArcs.Last().Data; var fragment = data as IFragment; var td = data as TraceData; if (fragment != null) { treeChart_HighlightSubtree(graphNode.Data.NodeAt(fragment.Index1)); } else if (td != null) { var nodes = graphNode.Data.IterateNodesPrefix().ToList(); treeChart_HighlightSubtree(nodes[td.LastSubtreeIndex], Color.Orange); treeChart_HighlightSubtree(nodes[td.LastFragmentIndex], Color.DodgerBlue); } } } public void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs args) { var visualNode = (VisualTreeNode)sender; var subtree = visualNode.Content; // highlight the selected subtree inside the displayed tree on the right hand side treeChart_ClearColors(); treeChart_HighlightSubtree(subtree); bool trace = genealogyGraphChart.TraceFragments; // check whether we are in 'trace' or 'match' mode if (trace) { // perform fragment tracing var graphNode = (IGenealogyGraphNode)genealogyGraphChart.SelectedGraphNode; var subtreeIndex = graphNode.Data.IterateNodesPrefix().ToList().IndexOf(subtree); var traceGraph = TraceCalculator.TraceSubtree(graphNode, subtreeIndex); if (traceGraph.Vertices.Any()) { genealogyGraphChart.UpdateEnabled = false; genealogyGraphChart.ClearArcs(); var genealogyNodes = traceGraph.Vertices.Select(v => Content.GetByContent(v.Data)); genealogyGraphChart.HighlightNodes(genealogyNodes, Color.Black, false); genealogyGraphChart.UpdateEnabled = true; genealogyGraphChart.EnforceUpdate(); MainFormManager.MainForm.ShowContent(traceGraph); // display the fragment graph on the screen } } else { // perform matching like it was done before // currently there is no possibility to specify the subtree matching criteria var trees = Content.Vertices.Select(x => x.Data); var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(subtree, comparer)); var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x)); graphChart_HighlightMatchingVertices(matchingVertices); } } private void graphChart_HighlightMatchingVertices(IEnumerable vertices) { genealogyGraphChart.Chart.UpdateEnabled = false; genealogyGraphChart.ClearPrimitives(); genealogyGraphChart.HighlightNodes(vertices); genealogyGraphChart.Chart.UpdateEnabled = true; genealogyGraphChart.Chart.EnforceUpdate(); } private void treeChart_ClearColors() { foreach (var node in SymbolicExpressionTreeChart.Tree.IterateNodesPrefix()) { var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node); if (visualNode != null) { visualNode.LineColor = Color.Black; visualNode.FillColor = Color.Transparent; } } SymbolicExpressionTreeChart.RepaintNodes(); } private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree, Color? color = null) { Color myColor = color ?? Color.RoyalBlue; foreach (var s in subtree.IterateNodesPrefix()) { var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s); visualNode.LineColor = myColor; foreach (var c in s.Subtrees) { var visualArc = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c); visualArc.LineColor = myColor; } } SymbolicExpressionTreeChart.RepaintNodes(); } private void navigateLeftButton_Click(object sender, EventArgs e) { var graphNode = (IGenealogyGraphNode)genealogyGraphChart.SelectedGraphNode; var inArcs = (List)((IVertex)graphNode).InArcs; if (inArcs.Count > 0) { genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode)inArcs[0].Source; } } private void navigateRightButton_Click(object sender, EventArgs e) { var graphNode = (IGenealogyGraphNode)genealogyGraphChart.SelectedGraphNode; var inArcs = (List)((IVertex)graphNode).InArcs; if (inArcs.Count > 0) { var data = inArcs.Last().Data; var fragment = (data as IFragment); var td = data as TraceData; if (fragment != null) { genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode)inArcs.Last().Source; } else if (td != null) { if (inArcs.Count == 1) { genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode)inArcs[0].Source; return; } // the first arc from inArcs will always represent the connection to the root parent // (tracing the body of the traced subtree) // therefore, in order to follow the correct non-root parent, we have to find the correct arc // But, the FragmentIndex recorded in the TraceData of the first arc has to match the SubtreeIndex recorded in the TraceData of the searched arc td = (TraceData)inArcs[0].Data; var f1 = (graphNode.Data).NodeAt(td.LastFragmentIndex); for (int i = 1; i < inArcs.Count; ++i) { td = (TraceData)inArcs[i].Data; var f2 = ((ISymbolicExpressionTree)inArcs[i].Source.Data).NodeAt(td.SubtreeIndex); // if the subtrees are the same we have found a match // note: this is not necessarily 100% correct if in the trace graph we have identical fragments on different arcs if (f1.Difference(f2) == null) { genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode)inArcs[i].Source; return; } } throw new InvalidOperationException("Error calculating the next step."); } } } } public class SymbolicDataAnalysisGenealogyGraphViewDesignable : GenealogyGraphView { } }