Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 7388 was 7388, checked in by bburlacu, 12 years ago

#1763: Added a new context option for leaf nodes (ConstantTreeNode or VariableTreeNode) to change the value or variable weight respectively.

  • Added new dialog: SymbolicExpressionTreeNodeChangeValueDialog
  • Added new SymbolicExpressionTreeNodeChanged event and handler
  • Changed the double click behavior to account for node value/weight changes

Overall the behavior has been slightly changed: if a node was folded(replaced by a ConstantTreeNode), then it is possible to change its value via the context menu. For all changed nodes the original value is kept in a dictionary, so the first double click will restore it. After that, a second double click will unfold the node.

File size: 13.0 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.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Common;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
30using HeuristicLab.MainForm.WindowsForms;
31
32namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
33  public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView {
34    private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> replacementNodes;
35    private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts;
36    private Dictionary<ISymbolicExpressionTreeNode, double> originalValues;
37    private bool updateInProgress = false;
38
39    public InteractiveSymbolicDataAnalysisSolutionSimplifierView() {
40      InitializeComponent();
41      this.replacementNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
42      this.nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
43      this.originalValues = new Dictionary<ISymbolicExpressionTreeNode, double>();
44      this.Caption = "Interactive Solution Simplifier";
45    }
46
47    public new ISymbolicDataAnalysisSolution Content {
48      get { return (ISymbolicDataAnalysisSolution)base.Content; }
49      set { base.Content = value; }
50    }
51
52    protected override void RegisterContentEvents() {
53      base.RegisterContentEvents();
54      Content.ModelChanged += new EventHandler(Content_ModelChanged);
55      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
56    }
57    protected override void DeregisterContentEvents() {
58      base.DeregisterContentEvents();
59      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
60      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
61    }
62
63    private void Content_ModelChanged(object sender, EventArgs e) {
64      OnModelChanged();
65    }
66    private void Content_ProblemDataChanged(object sender, EventArgs e) {
67      OnProblemDataChanged();
68    }
69
70    protected virtual void OnModelChanged() {
71      this.CalculateReplacementNodesAndNodeImpacts();
72    }
73
74    protected virtual void OnProblemDataChanged() {
75      this.CalculateReplacementNodesAndNodeImpacts();
76    }
77
78    protected override void OnContentChanged() {
79      base.OnContentChanged();
80      this.CalculateReplacementNodesAndNodeImpacts();
81      this.viewHost.Content = this.Content;
82    }
83
84    private void CalculateReplacementNodesAndNodeImpacts() {
85      if (Content != null && Content.Model != null && Content.ProblemData != null) {
86        var tree = Content.Model.SymbolicExpressionTree;
87        var replacementValues = CalculateReplacementValues(tree);
88        foreach (var pair in replacementValues) {
89          if (!(pair.Key is ConstantTreeNode)) {
90            replacementNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
91          }
92        }
93        nodeImpacts = CalculateImpactValues(Content.Model.SymbolicExpressionTree);
94
95        if (!updateInProgress) {
96          // automatically fold all branches with impact = 0
97          List<ISymbolicExpressionTreeNode> nodeList = Content.Model.SymbolicExpressionTree.Root.GetSubtree(0).IterateNodesPrefix().ToList();
98          foreach (var parent in nodeList) {
99            for (int subTreeIndex = 0; subTreeIndex < parent.SubtreeCount; subTreeIndex++) {
100              var child = parent.GetSubtree(subTreeIndex);
101              if (!(child.Symbol is Constant) && nodeImpacts[child].IsAlmost(0.0)) {
102                SwitchNodeWithReplacementNode(parent, subTreeIndex);
103              }
104            }
105          }
106        }
107
108        // show only interesting part of solution
109        if (tree.Root.SubtreeCount > 1)
110          this.treeChart.Tree = new SymbolicExpressionTree(tree.Root); // RPB + ADFs
111        else
112          this.treeChart.Tree = new SymbolicExpressionTree(tree.Root.GetSubtree(0).GetSubtree(0)); // 1st child of RPB
113        this.PaintNodeImpacts();
114      }
115    }
116
117    protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateReplacementValues(ISymbolicExpressionTree tree);
118    protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateImpactValues(ISymbolicExpressionTree tree);
119    protected abstract void UpdateModel(ISymbolicExpressionTree tree);
120
121    private ConstantTreeNode MakeConstantTreeNode(double value) {
122      Constant constant = new Constant();
123      constant.MinValue = value - 1;
124      constant.MaxValue = value + 1;
125      ConstantTreeNode constantTreeNode = (ConstantTreeNode)constant.CreateTreeNode();
126      constantTreeNode.Value = value;
127      return constantTreeNode;
128    }
129
130    private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
131      VisualSymbolicExpressionTreeNode visualTreeNode = (VisualSymbolicExpressionTreeNode)sender;
132      var tree = Content.Model.SymbolicExpressionTree;
133      // check if the node value/weight has been altered
134      // if so, the first double click will return the node to its original value/weight
135      // the next double click will replace the ConstantNode with the original SymbolicExpressionTreeNode
136      if (originalValues.ContainsKey(visualTreeNode.SymbolicExpressionTreeNode)) {
137        double value = originalValues[visualTreeNode.SymbolicExpressionTreeNode];
138        var subTree = visualTreeNode.SymbolicExpressionTreeNode;
139        if (subTree.Symbol is Constant)
140          (subTree as ConstantTreeNode).Value = value;
141        else if (subTree.Symbol is Variable)
142          (subTree as VariableTreeNode).Weight = value;
143        originalValues.Remove(subTree);
144        updateInProgress = true;
145        UpdateModel(tree);
146        updateInProgress = false;
147        return;
148      }
149
150      foreach (SymbolicExpressionTreeNode treeNode in tree.IterateNodesPostfix()) {
151        for (int i = 0; i < treeNode.SubtreeCount; i++) {
152          ISymbolicExpressionTreeNode subTree = treeNode.GetSubtree(i);
153          // only allow to replace nodes for which a replacement value is known (replacement value for ADF nodes are not available)
154          if (subTree == visualTreeNode.SymbolicExpressionTreeNode && replacementNodes.ContainsKey(subTree)) {
155            SwitchNodeWithReplacementNode(treeNode, i);
156
157            // show only interesting part of solution
158            if (tree.Root.SubtreeCount > 1)
159              this.treeChart.Tree = new SymbolicExpressionTree(tree.Root); // RPB + ADFs
160            else
161              this.treeChart.Tree = new SymbolicExpressionTree(tree.Root.GetSubtree(0).GetSubtree(0)); // 1st child of RPB
162
163            updateInProgress = true;
164            UpdateModel(tree);
165            updateInProgress = false;
166            return; // break all loops
167          }
168        }
169      }
170    }
171
172    private void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
173      if (e.Button == MouseButtons.Right) {
174        var node = (sender as VisualSymbolicExpressionTreeNode).SymbolicExpressionTreeNode;
175        var menu = treeChart.ContextMenuStrip;
176
177        bool flag = (node.Symbol is Constant || node.Symbol is Variable);
178
179        ToolStripItem[] items = menu.Items.Find("changeValueToolStripMenuItem", false);
180        ToolStripItem changeValueMenuItem = null;
181        if (items.Any())
182          changeValueMenuItem = items[0];
183        if (changeValueMenuItem != null) {
184          changeValueMenuItem.Enabled = flag;
185          changeValueMenuItem.Visible = flag;
186        }
187      }
188    }
189
190    private void treeChart_SymbolicExpressionTreeNodeChanged(object sender, EventArgs e) {
191      var tree = Content.Model.SymbolicExpressionTree;
192      var visualTreeNode = sender as VisualSymbolicExpressionTreeNode;
193      var subTree = visualTreeNode.SymbolicExpressionTreeNode;
194      string title = String.Empty;
195      double value = 0.0;
196
197      if (subTree.Symbol is Constant) {
198        title = "Change Constant Value";
199        value = (subTree as ConstantTreeNode).Value;
200      } else if (subTree.Symbol is Variable) {
201        title = "Change Weight Value";
202        value = (subTree as VariableTreeNode).Weight;
203      }
204
205      if (!originalValues.ContainsKey(subTree))
206        originalValues.Add(subTree, value);
207      var dialog = new ValueChangeDialog(title, Math.Round(value,4).ToString());
208      dialog.ShowDialog(this);
209      if (dialog.DialogResult == DialogResult.OK) {
210        value = double.Parse(dialog.NewValue);
211        if (subTree.Symbol is Constant)
212          (subTree as ConstantTreeNode).Value = value;
213        else if (subTree.Symbol is Variable)
214          (subTree as VariableTreeNode).Weight = value;
215        // show only interesting part of solution
216        treeChart.Tree = tree.Root.SubtreeCount > 1 ? new SymbolicExpressionTree(tree.Root) : new SymbolicExpressionTree(tree.Root.GetSubtree(0).GetSubtree(0));
217        updateInProgress = true;
218        UpdateModel(tree);
219        updateInProgress = false;
220      }
221    }
222
223    private void SwitchNodeWithReplacementNode(ISymbolicExpressionTreeNode parent, int subTreeIndex) {
224      ISymbolicExpressionTreeNode subTree = parent.GetSubtree(subTreeIndex);
225      parent.RemoveSubtree(subTreeIndex);
226      if (replacementNodes.ContainsKey(subTree)) {
227        var replacementNode = replacementNodes[subTree];
228        parent.InsertSubtree(subTreeIndex, replacementNode);
229        // exchange key and value
230        replacementNodes.Remove(subTree);
231        replacementNodes.Add(replacementNode, subTree);
232      }
233    }
234
235    private void PaintNodeImpacts() {
236      var impacts = nodeImpacts.Values;
237      double max = impacts.Max();
238      double min = impacts.Min();
239      foreach (ISymbolicExpressionTreeNode treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
240        if (!(treeNode is ConstantTreeNode) && nodeImpacts.ContainsKey(treeNode)) {
241          double impact = nodeImpacts[treeNode];
242          VisualSymbolicExpressionTreeNode visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
243
244          // impact = 0 if no change
245          // impact < 0 if new solution is better
246          // impact > 0 if new solution is worse
247          if (impact < 0.0) {
248            // min is guaranteed to be < 0
249            visualTree.FillColor = Color.FromArgb((int)(impact / min * 255), Color.Red);
250          } else if (impact.IsAlmost(0.0)) {
251            visualTree.FillColor = Color.White;
252          } else {
253            // max is guaranteed to be > 0
254            visualTree.FillColor = Color.FromArgb((int)(impact / max * 255), Color.Green);
255          }
256          visualTree.ToolTip += Environment.NewLine + "Node impact: " + impact;
257          var constantReplacementNode = replacementNodes[treeNode] as ConstantTreeNode;
258          if (constantReplacementNode != null) {
259            visualTree.ToolTip += Environment.NewLine + "Replacement value: " + constantReplacementNode.Value;
260          }
261        }
262      }
263      this.PaintCollapsedNodes();
264      this.treeChart.Repaint();
265    }
266
267    private void PaintCollapsedNodes() {
268      foreach (ISymbolicExpressionTreeNode treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
269        if (originalValues.ContainsKey(treeNode))
270          this.treeChart.GetVisualSymbolicExpressionTreeNode(treeNode).LineColor = Color.Blue;
271        else if (treeNode is ConstantTreeNode && replacementNodes.ContainsKey(treeNode))
272          this.treeChart.GetVisualSymbolicExpressionTreeNode(treeNode).LineColor = Color.DarkOrange;
273        else {
274          VisualSymbolicExpressionTreeNode visNode = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
275          if (visNode != null)
276            visNode.LineColor = Color.Black;
277        }
278      }
279    }
280
281    private void btnSimplify_Click(object sender, EventArgs e) {
282      SymbolicDataAnalysisExpressionTreeSimplifier simplifier = new SymbolicDataAnalysisExpressionTreeSimplifier();
283      var simplifiedExpressionTree = simplifier.Simplify(Content.Model.SymbolicExpressionTree);
284      UpdateModel(simplifiedExpressionTree);
285    }
286
287    protected abstract void btnOptimizeConstants_Click(object sender, EventArgs e);
288  }
289}
Note: See TracBrowser for help on using the repository browser.