source: branches/HeuristicLab.TreeSimplifier/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs @ 8409

Last change on this file since 8409 was 8409, checked in by bburlacu, 10 years ago

#1763: Fixed bug when pasting subtrees. Moved the InteractiveSymbolicExpressionTreeChart and dialogs in the HeuristicLab.Problems.DataAnalysis.Symbolic.Views namespace and renamed the impact values calculators to a more sensible name.

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