Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.TreeSimplifierView/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs @ 8250

Last change on this file since 8250 was 7784, checked in by bburlacu, 13 years ago

#1832: Moved replacement and impact values calculation code from view to separate files. Implemented simplifier actions: copy, cut, delete, insert node/subtree.

File size: 16.5 KB
RevLine 
[3915]1#region License Information
2/* HeuristicLab
[7259]3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3915]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;
[7411]24using System.ComponentModel;
[3915]25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Common;
[7784]29using HeuristicLab.Data;
[3915]30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[4068]31using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
[3915]32using HeuristicLab.MainForm.WindowsForms;
33
[5699]34namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
35  public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView {
[5729]36    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> replacementNodes;
[5699]37    private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts;
[7388]38    private Dictionary<ISymbolicExpressionTreeNode, double> originalValues;
[7784]39    private Dictionary<ISymbolicExpressionTreeNode, string> originalVariableNames;
[6113]40    private bool updateInProgress = false;
[7422]41    private ISymbolicExpressionTree model;
[3915]42
[5699]43    public InteractiveSymbolicDataAnalysisSolutionSimplifierView() {
[3915]44      InitializeComponent();
[5729]45      this.replacementNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
[5699]46      this.nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
[7388]47      this.originalValues = new Dictionary<ISymbolicExpressionTreeNode, double>();
[7784]48      this.originalVariableNames = new Dictionary<ISymbolicExpressionTreeNode, string>();
[3915]49      this.Caption = "Interactive Solution Simplifier";
50    }
51
[5699]52    public new ISymbolicDataAnalysisSolution Content {
53      get { return (ISymbolicDataAnalysisSolution)base.Content; }
[3915]54      set { base.Content = value; }
55    }
56
57    protected override void RegisterContentEvents() {
58      base.RegisterContentEvents();
59      Content.ModelChanged += new EventHandler(Content_ModelChanged);
60      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
61    }
62    protected override void DeregisterContentEvents() {
63      base.DeregisterContentEvents();
64      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
65      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
66    }
67
68    private void Content_ModelChanged(object sender, EventArgs e) {
[5699]69      OnModelChanged();
[3915]70    }
71    private void Content_ProblemDataChanged(object sender, EventArgs e) {
[5699]72      OnProblemDataChanged();
73    }
74
75    protected virtual void OnModelChanged() {
[7422]76      model = (model == null)
77                ? (ISymbolicExpressionTree)Content.Model.SymbolicExpressionTree.Clone()
78                : Content.Model.SymbolicExpressionTree;
79      this.CalculateReplacementNodesAndNodeImpacts(model);
80      this.PaintModel();
[3915]81    }
82
[5699]83    protected virtual void OnProblemDataChanged() {
84      this.CalculateReplacementNodesAndNodeImpacts();
[7422]85      this.PaintModel();
[5699]86    }
87
[3915]88    protected override void OnContentChanged() {
[7422]89      model = (model == null)
90          ? (ISymbolicExpressionTree)Content.Model.SymbolicExpressionTree.Clone()
91          : Content.Model.SymbolicExpressionTree;
[3915]92      base.OnContentChanged();
[7422]93      this.CalculateReplacementNodesAndNodeImpacts(model);
94      this.PaintModel();
[3915]95      this.viewHost.Content = this.Content;
96    }
97
98    private void CalculateReplacementNodesAndNodeImpacts() {
[7422]99      if (Content == null || Content.Model == null || Content.ProblemData == null) return;
100      var tree = model;
101      var replacementValues = CalculateReplacementValues(tree);
102      foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) {
103        replacementNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
104      }
105      nodeImpacts = CalculateImpactValues(tree);
106
107      if (!updateInProgress) {
108        // automatically fold all branches with impact = 0
109        List<ISymbolicExpressionTreeNode> nodeList = tree.Root.GetSubtree(0).IterateNodesPrefix().ToList();
110        foreach (var parent in nodeList) {
111          for (int subTreeIndex = 0; subTreeIndex < parent.SubtreeCount; subTreeIndex++) {
112            var child = parent.GetSubtree(subTreeIndex);
113            if (!(child.Symbol is Constant) && nodeImpacts[child].IsAlmost(0.0)) {
114              SwitchNodeWithReplacementNode(parent, subTreeIndex);
115            }
[5729]116          }
[5699]117        }
[7422]118      }
119      PaintModel();
120    }
[3915]121
[7422]122    private void CalculateReplacementNodesAndNodeImpacts(ISymbolicExpressionTree tree) {
123      var replacementValues = CalculateReplacementValues(tree);
124      foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) {
125        replacementNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
126      }
127      nodeImpacts = CalculateImpactValues(tree);
128
129      if (!updateInProgress) {
130        // automatically fold all branches with impact = 0
131        List<ISymbolicExpressionTreeNode> nodeList = tree.Root.GetSubtree(0).IterateNodesPrefix().ToList();
132        foreach (var parent in nodeList) {
133          for (int subTreeIndex = 0; subTreeIndex < parent.SubtreeCount; subTreeIndex++) {
134            var child = parent.GetSubtree(subTreeIndex);
135            if (!(child.Symbol is Constant) && nodeImpacts[child].IsAlmost(0.0)) {
136              SwitchNodeWithReplacementNode(parent, subTreeIndex);
[5455]137            }
138          }
139        }
[3915]140      }
[7422]141      PaintModel();
[3915]142    }
143
[7422]144    private void PaintModel() {
145      // show only interesting part of solution
146      this.treeChart.Tree = model.Root.SubtreeCount > 1 ? new SymbolicExpressionTree(model.Root) : new SymbolicExpressionTree(model.Root.GetSubtree(0).GetSubtree(0));
147      this.PaintNodeImpacts();
148    }
149
[5717]150    protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateReplacementValues(ISymbolicExpressionTree tree);
151    protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateImpactValues(ISymbolicExpressionTree tree);
152    protected abstract void UpdateModel(ISymbolicExpressionTree tree);
[3915]153
154    private ConstantTreeNode MakeConstantTreeNode(double value) {
155      Constant constant = new Constant();
156      constant.MinValue = value - 1;
157      constant.MaxValue = value + 1;
158      ConstantTreeNode constantTreeNode = (ConstantTreeNode)constant.CreateTreeNode();
159      constantTreeNode.Value = value;
160      return constantTreeNode;
161    }
162
163    private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
[7784]164      var visualNode = (VisualSymbolicExpressionTreeNode)sender;
165      var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.SymbolicExpressionTreeNode;
166      if (symbExprTreeNode == null) return;
[7422]167      var tree = model;
[7388]168      // check if the node value/weight has been altered
[7784]169      // if so, the first double click will return the node to its original value/weight/variable name
[7388]170      // the next double click will replace the ConstantNode with the original SymbolicExpressionTreeNode
[7784]171      if (originalVariableNames.ContainsKey(symbExprTreeNode)) {
172        var variable = (VariableTreeNode)symbExprTreeNode;
173        variable.VariableName = originalVariableNames[symbExprTreeNode];
174        originalVariableNames.Remove(variable);
[7388]175        updateInProgress = true;
176        UpdateModel(tree);
177        updateInProgress = false;
178        return;
179      }
[7784]180      if (originalValues.ContainsKey(symbExprTreeNode)) {
181        double value = originalValues[symbExprTreeNode];
182        if (symbExprTreeNode.Symbol is Constant)
183          ((ConstantTreeNode)symbExprTreeNode).Value = value;
184        else if (symbExprTreeNode.Symbol is Variable)
185          ((VariableTreeNode)symbExprTreeNode).Weight = value;
186        originalValues.Remove(symbExprTreeNode);
187        updateInProgress = true;
188        UpdateModel(tree);
189        updateInProgress = false;
190        return;
191      }
[5722]192      foreach (SymbolicExpressionTreeNode treeNode in tree.IterateNodesPostfix()) {
[6803]193        for (int i = 0; i < treeNode.SubtreeCount; i++) {
[5736]194          ISymbolicExpressionTreeNode subTree = treeNode.GetSubtree(i);
[5993]195          // only allow to replace nodes for which a replacement value is known (replacement value for ADF nodes are not available)
[7784]196          if (subTree == symbExprTreeNode && replacementNodes.ContainsKey(subTree)) {
[5729]197            SwitchNodeWithReplacementNode(treeNode, i);
[5993]198            // show only interesting part of solution
[7784]199            treeChart.Tree = tree.Root.SubtreeCount > 1 ? new SymbolicExpressionTree(tree.Root) : new SymbolicExpressionTree(tree.Root.GetSubtree(0).GetSubtree(0));
[6113]200            updateInProgress = true;
[6108]201            UpdateModel(tree);
[6113]202            updateInProgress = false;
[5993]203            return; // break all loops
[3915]204          }
205        }
206      }
207    }
208
[7372]209    private void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
[7784]210      // do stuff
211      treeChart.Repaint();
212    }
[7388]213
[7784]214    private void treeChart_OnInsertNodeContextMenuItemClicked(object sender, EventArgs e) {
215      // display the insert node dialog
216    }
[7388]217
[7784]218    private void treeChart_SymbolicExpressionTreeChanged(object sender, EventArgs e) {
219      CalculateReplacementNodesAndNodeImpacts(treeChart.Tree);
220      PaintModel();
[7388]221    }
[7372]222
[7388]223    private void treeChart_SymbolicExpressionTreeNodeChanged(object sender, EventArgs e) {
[7784]224      var dialog = (ValueChangeDialog)sender;
225      bool flag1 = false, flag2 = false;
226      if (dialog.Content is VariableTreeNode) {
227        var variable = (VariableTreeNode)dialog.Content;
228        var weight = double.Parse(dialog.NewValueTextBox.Text);
229        var name = (string)dialog.VariableNameComboBox.SelectedItem;
230        if (!variable.Weight.Equals(weight)) {
231          flag1 = true;
232          originalValues[variable] = variable.Weight;
233          variable.Weight = weight;
234        }
235        if (!variable.VariableName.Equals(name)) {
236          flag2 = true;
237          originalVariableNames[variable] = variable.VariableName;
238          variable.VariableName = name;
239        }
240      } else if (dialog.Content is ConstantTreeNode) {
241        var constant = (ConstantTreeNode)dialog.Content;
242        var value = double.Parse(dialog.NewValueTextBox.Text);
243        if (!constant.Value.Equals(value)) {
244          flag1 = true;
245          originalValues[constant] = constant.Value;
246          constant.Value = value;
[7388]247
[7784]248        }
[7372]249      }
[7784]250      if (flag1 || flag2) {
251        CalculateReplacementNodesAndNodeImpacts();
252        PaintModel();
253      }
[7372]254    }
255
[7784]256    private void treeChart_SymbolicExpressionTreeNodeInserted(object sender, EventArgs e) {
[7411]257    }
258
[5729]259    private void SwitchNodeWithReplacementNode(ISymbolicExpressionTreeNode parent, int subTreeIndex) {
[5736]260      ISymbolicExpressionTreeNode subTree = parent.GetSubtree(subTreeIndex);
261      parent.RemoveSubtree(subTreeIndex);
[5729]262      if (replacementNodes.ContainsKey(subTree)) {
263        var replacementNode = replacementNodes[subTree];
[5736]264        parent.InsertSubtree(subTreeIndex, replacementNode);
[5729]265        // exchange key and value
266        replacementNodes.Remove(subTree);
267        replacementNodes.Add(replacementNode, subTree);
268      }
[5455]269    }
270
[3915]271    private void PaintNodeImpacts() {
272      var impacts = nodeImpacts.Values;
273      double max = impacts.Max();
274      double min = impacts.Min();
[7422]275      foreach (ISymbolicExpressionTreeNode treeNode in model.IterateNodesPostfix()) {
[7411]276        VisualSymbolicExpressionTreeNode visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
277        bool flag1 = replacementNodes.ContainsKey(treeNode);
278        bool flag2 = originalValues.ContainsKey(treeNode);
279        bool flag3 = treeNode is ConstantTreeNode;
280
281        if (flag2) // constant or variable node was changed
282          visualTree.ToolTip += Environment.NewLine + "Original value: " + originalValues[treeNode];
[7784]283        else if (flag1 && flag3) // symbol node was folded to a constant
[7411]284          visualTree.ToolTip += Environment.NewLine + "Original node: " + replacementNodes[treeNode];
285
[4477]286        if (!(treeNode is ConstantTreeNode) && nodeImpacts.ContainsKey(treeNode)) {
[5729]287          double impact = nodeImpacts[treeNode];
[5722]288
[5717]289          // impact = 0 if no change
290          // impact < 0 if new solution is better
291          // impact > 0 if new solution is worse
292          if (impact < 0.0) {
[5729]293            // min is guaranteed to be < 0
[5717]294            visualTree.FillColor = Color.FromArgb((int)(impact / min * 255), Color.Red);
[5729]295          } else if (impact.IsAlmost(0.0)) {
296            visualTree.FillColor = Color.White;
[5717]297          } else {
[5729]298            // max is guaranteed to be > 0
[5717]299            visualTree.FillColor = Color.FromArgb((int)(impact / max * 255), Color.Green);
300          }
[3915]301          visualTree.ToolTip += Environment.NewLine + "Node impact: " + impact;
[5729]302          var constantReplacementNode = replacementNodes[treeNode] as ConstantTreeNode;
303          if (constantReplacementNode != null) {
304            visualTree.ToolTip += Environment.NewLine + "Replacement value: " + constantReplacementNode.Value;
305          }
[6108]306        }
[3915]307      }
308      this.PaintCollapsedNodes();
309      this.treeChart.Repaint();
310    }
311
312    private void PaintCollapsedNodes() {
[7422]313      foreach (ISymbolicExpressionTreeNode treeNode in model.IterateNodesPostfix()) {
[7411]314        bool flag1 = replacementNodes.ContainsKey(treeNode);
315        bool flag2 = originalValues.ContainsKey(treeNode);
316        if (flag1 && treeNode is ConstantTreeNode) {
317          this.treeChart.GetVisualSymbolicExpressionTreeNode(treeNode).LineColor = flag2 ? Color.DarkViolet : Color.DarkOrange;
318        } else if (flag2) {
319          this.treeChart.GetVisualSymbolicExpressionTreeNode(treeNode).LineColor = Color.DodgerBlue;
[4477]320        }
[3915]321      }
322    }
[3927]323
324    private void btnSimplify_Click(object sender, EventArgs e) {
[7784]325      var simplifier = new SymbolicDataAnalysisExpressionTreeSimplifier();
[7422]326      var simplifiedExpressionTree = simplifier.Simplify(model);
[5722]327      UpdateModel(simplifiedExpressionTree);
[3927]328    }
[6256]329
[7422]330    protected abstract void btnOptimizeConstants_Click(object sender, EventArgs e);
331
[7411]332    private void btnPrune_Click(object sender, EventArgs e) {
[7422]333      btnPrune.Enabled = false;
[7411]334      backgroundWorker1.RunWorkerAsync();
335    }
336
337    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
[7422]338      var worker = sender as BackgroundWorker;
[7411]339      PruneTree(worker);
340    }
341
342    private void PruneTree(BackgroundWorker worker) {
[7422]343      var tree = model;
[7784]344      // get all tree nodes starting from depth 2 (below the root and start nodes)
345      foreach (var node in GetNodesAtDepth(tree, new IntRange(2, tree.Depth))) {
[7411]346        if (worker.CancellationPending)
347          break; // pruning cancelled
348        if (!(node.Symbol is Constant) && nodeImpacts.ContainsKey(node) && nodeImpacts[node] < 0.001) {
349          SwitchNodeWithReplacementNode(node.Parent, node.Parent.IndexOfSubtree(node));
[7422]350          nodeImpacts = CalculateImpactValues(tree);
351          // we do not refresh the replacementValues because they won't change when folding nodes with such low impacts (<0.001)
[7411]352        }
353      }
354    }
355
356    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
357      if (e.Cancelled) {
358        // The user canceled the operation.
359      } else if (e.Error != null) {
360        // There was an error during the operation.
361        // Error-handling
362      } else {
363        // The operation completed normally. We can update the model
[7422]364        UpdateModel(model);
[7411]365      }
[7422]366      btnPrune.Enabled = true;
[7411]367    }
[7422]368
369    #region helpers
[7784]370    private static IEnumerable<ISymbolicExpressionTreeNode> GetNodesAtDepth(ISymbolicExpressionTree tree, IntRange depthRange) {
371      var treeDepth = tree.Root.GetDepth();
372      return from node in tree.Root.IterateNodesPostfix()
373             let depth = treeDepth - node.GetDepth()
374             where depthRange.Start <= depth
375             where depth <= depthRange.End
376             select node;
[7422]377    }
378    #endregion
[3915]379  }
[7784]380}
Note: See TracBrowser for help on using the repository browser.