Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 8935 was 8935, checked in by bburlacu, 11 years ago

#1763: Bugfixes and refactoring as suggested in the comments above.

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