#region License Information
/* HeuristicLab
* Copyright (C) 2002-2010 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.Core.Views;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
using HeuristicLab.MainForm;
using HeuristicLab.Problems.DataAnalysis.Symbolic;
using HeuristicLab.Visualization;
namespace HeuristicLab.EvolutionaryTracking.Views {
[View("SymbolicExpressionTreeGenealogyGraph")]
[Content(typeof(SymbolicExpressionTreeGenealogyGraph), IsDefaultView = true)]
public sealed partial class GenealogyGraphView : ItemView {
private VisualSymbolicExpressionTreeNode selectedVisualSymbExprTreeNode;
public new SymbolicExpressionTreeGenealogyGraph Content {
get { return (SymbolicExpressionTreeGenealogyGraph)base.Content; }
set { base.Content = value; }
}
private Dictionary clonedNodeMap;
public GenealogyGraphView()
: base() {
InitializeComponent();
// set button icons here because if set in the designer file, they get overwritten
this.moveModeButton.Image = Common.Resources.VSImageLibrary.Pointer;
this.zoomModeButton.Image = Common.Resources.VSImageLibrary.Zoom;
this.selectModeButton.Image = Common.Resources.VSImageLibrary.Object;
similarityModeSelector.SelectedIndex = 0; // set default similarity mode to "exact"
}
protected override void DeregisterContentEvents() {
// TODO: Deregister your event handlers here
genealogyGraphChart.GenealogyGraphNodeClicked -= graphChart_GenealogyGraphNodeClicked;
symbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked;
base.DeregisterContentEvents();
}
protected override void RegisterContentEvents() {
base.RegisterContentEvents();
// TODO: Register your event handlers here
genealogyGraphChart.GenealogyGraphNodeClicked += graphChart_GenealogyGraphNodeClicked;
symbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked;
symbolicExpressionTreeChart.SymbolicExpressionTreeNodeDoubleClicked += treeChart_SymbolicExpressionTreeNodeDoubleClicked;
}
#region Event Handlers (Content)
// TODO: Put event handlers of the content here
protected override void OnContentChanged() {
base.OnContentChanged();
if (Content == null)
genealogyGraphChart.Graph = null;
else {
genealogyGraphChart.Graph = Content;
var best = Content.Nodes.OrderByDescending(x => x.Quality).First();
symbolicExpressionTreeChart.Tree = best.SymbolicExpressionTree;
}
}
private void Content_GraphChanged(object sender, EventArgs e) {
}
protected override void SetEnabledStateOfControls() {
base.SetEnabledStateOfControls();
genealogyGraphChart.Enabled = Content != null;
}
#endregion
#region Event Handlers (child controls)
// TODO: Put event handlers of child controls here.
private void graphChart_GenealogyGraphNodeClicked(object sender, MouseEventArgs e) {
// the type hierarchy goes like this: VisualGenealogyGraphNode --> GenealogyGraphNode --> symbolicExpressionTree
var visualGenealogyGraphNode = (VisualGenealogyGraphNode)sender;
var genealogyGraphNode = (SymbolicExpressionGenealogyGraphNode)visualGenealogyGraphNode.Data;
symbolicExpressionTreeChart.Tree = genealogyGraphNode.SymbolicExpressionTree;
// highlight the relevant fragment in the symbolic expression tree
selectedVisualSymbExprTreeNode = null;
bool repaint = false;
// paint highlighted nodes in symbolic expression tree
if (selectedVisualSymbExprTreeNode != null) {
// clear selected subtree from the tree chart
var nodes = symbolicExpressionTreeChart.Tree.IterateNodesBreadth() as List;
var fragments = selectedVisualSymbExprTreeNode.SymbolicExpressionTreeNode.IterateNodesBreadth() as List;
var similarityLevel = Enum.GetNames(typeof(SimilarityLevel))[similarityModeSelector.SelectedIndex];
int index = SymbolicExpressionTreeMatching.FindMatch(nodes, fragments, (SimilarityLevel)Enum.Parse(typeof(SimilarityLevel), similarityLevel));
if (index != -1) {
selectedVisualSymbExprTreeNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(nodes[index]);
var subtree = selectedVisualSymbExprTreeNode.SymbolicExpressionTreeNode;
foreach (var node in subtree.IterateNodesBreadth()) {
var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
visualNode.LineColor = Color.Blue;
}
repaint = true;
}
}
// paint graph nodes
var tree = symbolicExpressionTreeChart.Tree;
var graphNodes = Content.Nodes.Where(n => n.SymbolicExpressionTree == tree).ToList();
if (graphNodes.Count > 0) {
foreach (var graphNode in graphNodes)
if (graphNode != null && graphNode.InEdges != null) {
var arc = graphNode.InEdges.Find(a => a.Data != null);
if (arc != null) {
var fragment = arc.Data as ISymbolicExpressionTreeNode;
foreach (var node in fragment.IterateNodesBreadth()) {
var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
if (visualNode == null)
continue;
visualNode.LineColor = Color.Orange;
}
}
repaint = true;
}
}
if (repaint)
symbolicExpressionTreeChart.Repaint();
}
private void moveModeButton_CheckedChanged(object sender, EventArgs e) {
var btn = (RadioButton)sender;
if (btn.Checked) { genealogyGraphChart.Chart.Mode = ChartMode.Move; }
}
private void zoomModeButton_CheckedChanged(object sender, EventArgs e) {
var btn = (RadioButton)sender;
if (btn.Checked) { genealogyGraphChart.Chart.Mode = ChartMode.Zoom; }
}
private void selectModeButton_CheckedChanged(object sender, EventArgs e) {
var btn = (RadioButton)sender;
if (btn.Checked) { genealogyGraphChart.Chart.Mode = ChartMode.Select; }
}
private void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
ISymbolicExpressionTreeNode selectedSubtree = null;
genealogyGraphChart.Chart.UpdateEnabled = false;
switch (e.Button) {
case MouseButtons.Left: {
selectedVisualSymbExprTreeNode = (VisualSymbolicExpressionTreeNode)sender;
if (selectedVisualSymbExprTreeNode == null) return;
// find out which individuals in the genealogy graph contain this specific subtree
selectedSubtree = selectedVisualSymbExprTreeNode.SymbolicExpressionTreeNode;
// clone every node in the selected subtree so that edit operations are possible without altering the original subtree
// save the originalNode-->clone mapping to make it easier to work with subtrees
if (clonedNodeMap == null)
clonedNodeMap = new Dictionary();
clonedNodeMap.Clear();
var selectedSubtreeClone = selectedSubtree.Clone() as SymbolicExpressionTreeNode;
var subtreeNodes = selectedSubtree.IterateNodesPostfix().ToList();
var cloneNodes = selectedSubtreeClone.IterateNodesPostfix().ToList();
for (int i = 0; i != subtreeNodes.Count; ++i)
clonedNodeMap.Add(subtreeNodes[i], cloneNodes[i]);
// highlight subtree nodes in the tree chart
foreach (var node in symbolicExpressionTreeChart.Tree.IterateNodesPostfix()) {
var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
visualNode.FillColor = Color.Transparent;
}
selectedSubtree.ForEachNodePostfix(node => {
symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node).FillColor = Color.LightBlue;
});
}
break;
case MouseButtons.Middle: {
var visualNode = (VisualSymbolicExpressionTreeNode)sender;
if (selectedVisualSymbExprTreeNode == null || selectedVisualSymbExprTreeNode == visualNode)
return;
selectedSubtree = clonedNodeMap[selectedVisualSymbExprTreeNode.SymbolicExpressionTreeNode];
var selectedNode = visualNode.SymbolicExpressionTreeNode;
if (clonedNodeMap.ContainsKey(selectedNode)) {
var selected = clonedNodeMap[selectedNode];
var parent = selected.Parent;
parent.RemoveSubtree(parent.IndexOfSubtree(selected));
selectedNode.ForEachNodePostfix(node => {
symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node).FillColor = Color.Transparent;
clonedNodeMap.Remove(node);
});
}
}
break;
}
// update visual graph nodes that contain matching trees
Color[] colors = { Color.LightSkyBlue, Color.PaleGreen, Color.Tan };
genealogyGraphChart.ClearAllNodes(); // clear node colors
// color each graph node according to the degree to which it matches the selected tree fragment
var similarityValues = Enum.GetValues(typeof(SimilarityLevel)).Cast().ToList();
foreach (var graphNode in genealogyGraphChart.Graph.Nodes) {
var tree = graphNode.SymbolicExpressionTree;
for (int i = 0; i != similarityValues.Count; ++i) {
if (tree.ContainsFragment(selectedSubtree, similarityValues[i])) {
genealogyGraphChart.HighlightNode(graphNode, colors[i]);
break;
}
}
}
genealogyGraphChart.Chart.UpdateEnabled = true;
genealogyGraphChart.Chart.EnforceUpdate();
// refresh the tree chart
symbolicExpressionTreeChart.Repaint();
}
private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
}
private void similarityModeSelector_SelectedIndexChanged(object sender, EventArgs e) {
if (selectedVisualSymbExprTreeNode == null) return;
var treeNode = selectedVisualSymbExprTreeNode.SymbolicExpressionTreeNode;
var similarityLevel = Enum.GetNames(typeof(SimilarityLevel))[similarityModeSelector.SelectedIndex];
var owners = genealogyGraphChart.Graph.TraceFragment(treeNode, (SimilarityLevel)Enum.Parse(typeof(SimilarityLevel), similarityLevel)).ToList();
if (owners.Any()) {
genealogyGraphChart.Chart.UpdateEnabled = false;
genealogyGraphChart.ClearAllNodes(); // clear the fill color of all nodes
genealogyGraphChart.HighlightNodes(owners, Color.LightSkyBlue);
// highlight matching individuals from the genealogy
genealogyGraphChart.Chart.UpdateEnabled = true;
}
genealogyGraphChart.Chart.EnforceUpdate();
// highlight subtree nodes in the tree chart
foreach (var node in symbolicExpressionTreeChart.Tree.IterateNodesPostfix()) {
var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
visualNode.FillColor = Color.Transparent;
}
foreach (var node in treeNode.IterateNodesPostfix()) {
var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
visualNode.FillColor = Color.LightBlue;
}
}
#endregion
private void inDegreeButton_Click(object sender, EventArgs e) {
genealogyGraphChart.HighlightInDegree();
}
private void outDegreeButton_Click(object sender, EventArgs e) {
genealogyGraphChart.HighlightOutDegree();
}
}
}