Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
07/04/14 13:38:38 (10 years ago)
Author:
bburlacu
Message:

#1763: Introduced tree editing functionality directly into the trunk code, with minor changes: simplified drawing (eg when highlighting subtrees from the clipboard), fixed small bug in MinArity function. The branch can be deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs

    r10799 r11086  
    11#region License Information
    22/* HeuristicLab
    3  * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3 * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44 *
    55 * This file is part of HeuristicLab.
     
    3333  public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView {
    3434    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes;
     35    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> changedNodes;
    3536    private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts;
     37
    3638    private enum TreeState { Valid, Invalid }
    37 
    38     public InteractiveSymbolicDataAnalysisSolutionSimplifierView() {
     39    private TreeState treeState;
     40
     41    protected InteractiveSymbolicDataAnalysisSolutionSimplifierView() {
    3942      InitializeComponent();
    4043      foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     44      changedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    4145      nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
    4246      this.Caption = "Interactive Solution Simplifier";
     47
     48      // initialize the tree modifier that will be used to perform edit operations over the tree
     49      treeChart.ModifyTree = Modify;
     50    }
     51
     52    /// <summary>
     53    /// Remove, Replace or Insert subtrees
     54    /// </summary>
     55    /// <param name="tree">The symbolic expression tree</param>
     56    /// <param name="parent">The insertion point (ie, the parent node who will receive a new child)</param>
     57    /// <param name="oldChild">The subtree to be replaced</param>
     58    /// <param name="newChild">The replacement subtree</param>
     59    /// <param name="removeSubtree">Flag used to indicate if whole subtrees should be removed (default behavior), or just the subtree root</param>
     60    private void Modify(ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode parent,
     61      ISymbolicExpressionTreeNode oldChild, ISymbolicExpressionTreeNode newChild, bool removeSubtree = true) {
     62      if (oldChild == null && newChild == null)
     63        throw new ArgumentNullException("Cannot deduce operation type from the arguments. Please provide non null operands.");
     64      if (oldChild == null) {
     65        // insertion operation
     66        parent.AddSubtree(newChild);
     67        newChild.Parent = parent;
     68      } else if (newChild == null) {
     69        // removal operation
     70        parent.RemoveSubtree(parent.IndexOfSubtree(oldChild));
     71        if (!removeSubtree) {
     72          for (int i = oldChild.SubtreeCount - 1; i >= 0; --i) {
     73            var subtree = oldChild.GetSubtree(i);
     74            oldChild.RemoveSubtree(i);
     75            parent.AddSubtree(subtree);
     76          }
     77        }
     78      } else {
     79        // replacement operation
     80        var replacementIndex = parent.IndexOfSubtree(oldChild);
     81        parent.RemoveSubtree(replacementIndex);
     82        parent.InsertSubtree(replacementIndex, newChild);
     83        newChild.Parent = parent;
     84        if (changedNodes.ContainsKey(oldChild)) {
     85          changedNodes.Add(newChild, changedNodes[oldChild]); // so that on double click the original node is restored
     86          changedNodes.Remove(oldChild);
     87        } else {
     88          changedNodes.Add(newChild, oldChild);
     89        }
     90      }
     91      treeState = IsValid(tree) ? TreeState.Valid : TreeState.Invalid;
     92      switch (treeState) {
     93        case TreeState.Valid:
     94          this.grpViewHost.Enabled = true;
     95          UpdateModel(Content.Model.SymbolicExpressionTree);
     96          break;
     97        case TreeState.Invalid:
     98          this.grpViewHost.Enabled = false;
     99          break;
     100      }
     101    }
     102
     103    // the optimizer always assumes 2 children for multiplication and addition nodes
     104    // thus, we enforce that the tree stays valid so that the constant optimization won't throw an exception
     105    // by returning 2 as the minimum allowed arity for addition and multiplication symbols
     106    private readonly Func<ISymbol, int> GetMinArity = symbol => {
     107      var min = symbol.MinimumArity;
     108      if (symbol is Multiplication || symbol is Division) return Math.Max(2, min);
     109      return min;
     110    };
     111    private bool IsValid(ISymbolicExpressionTree tree) {
     112      treeChart.Tree = tree;
     113      treeChart.Repaint();
     114      bool valid = !tree.IterateNodesPostfix().Any(node => node.SubtreeCount < GetMinArity(node.Symbol) || node.SubtreeCount > node.Symbol.MaximumArity);
     115      if (valid) {
     116        btnOptimizeConstants.Enabled = true;
     117        btnSimplify.Enabled = true;
     118        treeStatusValue.Text = "Valid";
     119        treeStatusValue.ForeColor = Color.Green;
     120      } else {
     121        btnOptimizeConstants.Enabled = false;
     122        btnSimplify.Enabled = false;
     123        treeStatusValue.Text = "Invalid";
     124        treeStatusValue.ForeColor = Color.Red;
     125      }
     126      this.Refresh();
     127      return valid;
    43128    }
    44129
     
    83168
    84169      var impactAndReplacementValues = CalculateImpactAndReplacementValues(tree);
    85       nodeImpacts = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item1);
    86170      var replacementValues = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item2);
    87171      foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) {
    88172        foldedNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
    89173      }
     174      nodeImpacts = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item1);
    90175      PaintNodeImpacts();
    91176    }
     
    104189
    105190    private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
     191      if (treeState == TreeState.Invalid) return;
    106192      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
    107       if (visualNode.Content == null) { throw new Exception("Visual node content cannot be null."); }
     193      if (visualNode.Content == null) { throw new Exception("VisualNode content cannot be null."); }
    108194      var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.Content;
    109       if (!foldedNodes.ContainsKey(symbExprTreeNode)) return; // constant nodes cannot be folded
     195      var tree = Content.Model.SymbolicExpressionTree;
    110196      var parent = symbExprTreeNode.Parent;
    111197      int indexOfSubtree = parent.IndexOfSubtree(symbExprTreeNode);
    112       SwitchNodeWithReplacementNode(parent, indexOfSubtree);
    113       UpdateModel(Content.Model.SymbolicExpressionTree);
     198      if (changedNodes.ContainsKey(symbExprTreeNode)) {
     199        // undo node change
     200        parent.RemoveSubtree(indexOfSubtree);
     201        var originalNode = changedNodes[symbExprTreeNode];
     202        parent.InsertSubtree(indexOfSubtree, originalNode);
     203        changedNodes.Remove(symbExprTreeNode);
     204      } else if (foldedNodes.ContainsKey(symbExprTreeNode)) {
     205        // undo node folding
     206        SwitchNodeWithReplacementNode(parent, indexOfSubtree);
     207      }
     208      UpdateModel(tree);
    114209    }
    115210
     
    130225      double max = impacts.Max();
    131226      double min = impacts.Min();
    132       foreach (var treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
     227      foreach (ISymbolicExpressionTreeNode treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
    133228        VisualTreeNode<ISymbolicExpressionTreeNode> visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
    134229
    135230        if (!(treeNode is ConstantTreeNode) && nodeImpacts.ContainsKey(treeNode)) {
    136           visualTree.ToolTip = visualTree.Content.ToString(); // to avoid duplicate tooltips
     231          visualTree.ToolTip = visualTree.Content.ToString();
    137232          double impact = nodeImpacts[treeNode];
    138233
     
    156251        }
    157252        if (visualTree != null)
    158           if (treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) {
     253          if (changedNodes.ContainsKey(treeNode)) {
     254            visualTree.LineColor = Color.DodgerBlue;
     255          } else if (treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) {
    159256            visualTree.LineColor = Color.DarkOrange;
    160257          }
Note: See TracChangeset for help on using the changeset viewer.