source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs @ 6999

Last change on this file since 6999 was 6999, checked in by mkommend, 11 years ago

#1479:

  • Renamed symbolic classification sample.
  • Updated samples unit test to use new features of the SymbolicExpressionGrammar.
  • Updated symbolic regression and classification sample.
  • Filtered symbolic in AllowedChildSymbolsView.
File size: 15.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.PluginInfrastructure;
30
31namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
32  public sealed partial class SymbolicExpressionGrammarAllowedChildSymbolsControl : UserControl {
33    private ObservableList<ISymbolicExpressionTreeNode> selectedSymbolicExpressionTreeNodes;
34
35    public SymbolicExpressionGrammarAllowedChildSymbolsControl() {
36      InitializeComponent();
37      selectedSymbolicExpressionTreeNodes = new ObservableList<ISymbolicExpressionTreeNode>();
38    }
39
40    private ISymbolicExpressionGrammar grammar;
41    public ISymbolicExpressionGrammar Grammar {
42      get { return grammar; }
43      set {
44        if (grammar != value) {
45          if (grammar != null) DeregisterGrammarEvents();
46          grammar = value;
47          if (grammar != null) RegisterGrammarEvents();
48          OnGrammarChanged();
49        }
50      }
51    }
52
53    private ISymbol symbol;
54    public ISymbol Symbol {
55      get { return symbol; }
56      set {
57        if (symbol != value) {
58          if (value != null && grammar == null) throw new InvalidOperationException("grammar is null");
59          if (value != null && !grammar.ContainsSymbol(value)) throw new ArgumentException("grammar does not contain symbol.");
60          symbol = value;
61          OnSymbolChanged();
62        }
63      }
64    }
65
66    private void RegisterGrammarEvents() {
67      grammar.Changed += new EventHandler(Grammar_Changed);
68    }
69    private void DeregisterGrammarEvents() {
70      grammar.Changed -= new EventHandler(Grammar_Changed);
71    }
72
73    private void Grammar_Changed(object sender, EventArgs e) {
74      if (Grammar == null) return;
75      if (Symbol == null) return;
76      if (Symbol != null && !Grammar.ContainsSymbol(Symbol)) Symbol = null;
77      else BuildAllowedChildSymbolsTree();
78    }
79
80    private void OnGrammarChanged() {
81      if (Grammar == null) {
82        symbolicExpressionTreeChart.Tree = null;
83        Symbol = null;
84      }
85    }
86    private void OnSymbolChanged() {
87      if (Symbol == null) symbolicExpressionTreeChart.Tree = null;
88      else BuildAllowedChildSymbolsTree();
89    }
90
91    private void BuildAllowedChildSymbolsTree() {
92      var tree = new SymbolicExpressionTree(new SymbolicExpressionTreeNode(Symbol));
93
94      symbolicExpressionTreeChart.SuspendRepaint = true;
95      if (Grammar.GetMaximumSubtreeCount(Symbol) > 0) {
96        for (int i = 0; i < Grammar.GetMaximumSubtreeCount(Symbol); i++) {
97          var node = new DummySymbol("Subtree " + i).CreateTreeNode();
98          var groupSymbols = grammar.GetAllowedChildSymbols(Symbol, i).OfType<GroupSymbol>().ToList();
99          foreach (var childSymbol in Grammar.GetAllowedChildSymbols(Symbol, i)) {
100            if (!groupSymbols.Any(g => g != childSymbol && g.Flatten().Contains(childSymbol)))
101              node.AddSubtree(new SymbolicExpressionTreeNode(childSymbol));
102          }
103          tree.Root.AddSubtree(node);
104        }
105      }
106      symbolicExpressionTreeChart.Tree = tree;
107
108      foreach (var subtreeNode in tree.Root.Subtrees) {
109        foreach (var allowedChildNode in subtreeNode.Subtrees) {
110          var visualLine = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(subtreeNode, allowedChildNode);
111          visualLine.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
112        }
113      }
114
115      for (int i = Grammar.GetMinimumSubtreeCount(symbol); i < Grammar.GetMaximumSubtreeCount(symbol); i++) {
116        var subtreeNode = tree.Root.GetSubtree(i);
117        var visualTreeNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(subtreeNode);
118        visualTreeNode.TextColor = Color.Gray;
119        visualTreeNode.LineColor = Color.LightGray;
120
121        var visualLine = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(tree.Root, subtreeNode);
122        visualLine.LineColor = Color.LightGray;
123
124        foreach (var allowedChildNode in subtreeNode.Subtrees) {
125          visualTreeNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(allowedChildNode);
126          visualTreeNode.TextColor = Color.Gray;
127          visualTreeNode.LineColor = Color.LightGray;
128
129          visualLine = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(subtreeNode, allowedChildNode);
130          visualLine.LineColor = Color.LightGray;
131        }
132      }
133
134      symbolicExpressionTreeChart.SuspendRepaint = false;
135      UpdateSelectedSymbolicExpressionTreeNodes();
136    }
137
138    private void UpdateSelectedSymbolicExpressionTreeNodes() {
139      foreach (var node in symbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
140        var visualNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
141        if (!selectedSymbolicExpressionTreeNodes.Contains(node)) visualNode.FillColor = Color.White;
142        else visualNode.FillColor = Color.LightSteelBlue;
143      }
144      symbolicExpressionTreeChart.Repaint();
145    }
146
147    private void symbolicExpressionTreeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
148      if ((Control.ModifierKeys & Keys.Control) == 0)
149        selectedSymbolicExpressionTreeNodes.Clear();
150
151      VisualSymbolicExpressionTreeNode clickedNode = (VisualSymbolicExpressionTreeNode)sender;
152      var selectedNode = clickedNode.SymbolicExpressionTreeNode;
153      if (selectedNode.SubtreeCount == 0) {
154        if (!selectedSymbolicExpressionTreeNodes.Contains(selectedNode))
155          selectedSymbolicExpressionTreeNodes.Add(selectedNode);
156        else
157          selectedSymbolicExpressionTreeNodes.Remove(selectedNode);
158      }
159
160      UpdateSelectedSymbolicExpressionTreeNodes();
161    }
162
163    private void symbolicExpressionTreeChart_KeyDown(object sender, KeyEventArgs e) {
164      if (e.KeyCode == Keys.Delete) {
165        var root = symbolicExpressionTreeChart.Tree.Root;
166        Grammar.StartGrammarManipulation();
167        foreach (var node in selectedSymbolicExpressionTreeNodes) {
168          int argIndex = root.IndexOfSubtree(node.Parent);
169          Grammar.RemoveAllowedChildSymbol(root.Symbol, node.Symbol, argIndex);
170        }
171
172        selectedSymbolicExpressionTreeNodes.Clear();
173        Grammar.FinishedGrammarManipulation();
174      }
175    }
176
177    #region drag & drop operations
178    private bool validDragOperation;
179    private void symbolicExpressionTreeChart_DragEnter(object sender, DragEventArgs e) {
180      validDragOperation = false;
181      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
182      var symbol = data as ISymbol;
183      var symbols = data as IEnumerable<ISymbol>;
184      if (symbol != null && !(symbol is IReadOnlySymbol) && Grammar.ContainsSymbol(symbol)) validDragOperation = true;
185      else if (symbols != null && symbols.All(s => !(symbol is IReadOnlySymbol) && Grammar.ContainsSymbol(s))) validDragOperation = true;
186    }
187
188    private void symbolicExpressionTreeChart_DragOver(object sender, DragEventArgs e) {
189      e.Effect = DragDropEffects.None;
190      if (validDragOperation) {
191        Point coordinates = symbolicExpressionTreeChart.PointToClient(new Point(e.X, e.Y));
192        var visualNode = symbolicExpressionTreeChart.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
193        if (visualNode != null) {
194          var node = visualNode.SymbolicExpressionTreeNode;
195          var root = symbolicExpressionTreeChart.Tree.Root;
196          if (root.Symbol is ProgramRootSymbol) return;
197          if (node == root || node.Parent == root) e.Effect = DragDropEffects.Copy;
198        }
199      }
200    }
201
202    private void symbolicExpressionTreeChart_DragDrop(object sender, DragEventArgs e) {
203      Point coordinates = symbolicExpressionTreeChart.PointToClient(new Point(e.X, e.Y));
204      var node = symbolicExpressionTreeChart.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
205      var root = symbolicExpressionTreeChart.Tree.Root;
206
207      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
208      var symbol = data as ISymbol;
209      var symbols = data as IEnumerable<ISymbol>;
210
211      if (node.SymbolicExpressionTreeNode == root) {
212        if (symbol != null)
213          Grammar.AddAllowedChildSymbol(root.Symbol, symbol);
214        else if (symbols != null)
215          foreach (var s in symbols) Grammar.AddAllowedChildSymbol(root.Symbol, s);
216      } else {
217        int argumentIndex = root.IndexOfSubtree(node.SymbolicExpressionTreeNode);
218        if (symbol != null)
219          Grammar.AddAllowedChildSymbol(root.Symbol, symbol, argumentIndex);
220        else if (symbols != null)
221          foreach (var s in symbols) Grammar.AddAllowedChildSymbol(root.Symbol, s, argumentIndex);
222      }
223      BuildAllowedChildSymbolsTree();
224    }
225    #endregion
226
227    #region draw and handle root node with buttons to manipulate the subtree count
228    private RectangleF increaseMinimumSubtreeCountRectangle;
229    private RectangleF decreaseMinimumSubtreeCountRectangle;
230    private RectangleF increaseMaximumSubtreeCountRectangle;
231    private RectangleF decreaseMaximumSubtreeCountRectangle;
232    private void allowedChildSymbolsControl_Paint(object sender, PaintEventArgs e) {
233      increaseMinimumSubtreeCountRectangle = RectangleF.Empty;
234      decreaseMinimumSubtreeCountRectangle = RectangleF.Empty;
235      increaseMaximumSubtreeCountRectangle = RectangleF.Empty;
236      decreaseMaximumSubtreeCountRectangle = RectangleF.Empty;
237
238      if (Grammar == null) return;
239      if (symbolicExpressionTreeChart.Tree == null) return;
240
241      var rootNode = symbolicExpressionTreeChart.Tree.Root;
242      var visualRootNode = symbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(rootNode);
243      var graphics = e.Graphics;
244
245      if (rootNode.Symbol is IReadOnlySymbol) return;
246      if (rootNode.Symbol.MinimumArity == rootNode.Symbol.MaximumArity) return;
247
248      using (Pen pen = new Pen(Color.Black)) {
249        using (Font font = new Font("Times New Roman", 8)) {
250          var stringFormat = new StringFormat();
251          stringFormat.Alignment = StringAlignment.Center;
252          stringFormat.LineAlignment = StringAlignment.Center;
253          int spacing = 5;
254          int size = (visualRootNode.Height - spacing * 3) / 2;
255
256          increaseMinimumSubtreeCountRectangle = new RectangleF(visualRootNode.X - spacing - size, visualRootNode.Y + spacing, size, size);
257          decreaseMinimumSubtreeCountRectangle = new RectangleF(visualRootNode.X - spacing - size, visualRootNode.Y + size + 2 * spacing, size, size);
258          increaseMaximumSubtreeCountRectangle = new RectangleF(visualRootNode.X + visualRootNode.Width + spacing, visualRootNode.Y + spacing, size, size);
259          decreaseMaximumSubtreeCountRectangle = new RectangleF(visualRootNode.X + visualRootNode.Width + spacing, visualRootNode.Y + size + 2 * spacing, size, size);
260
261          pen.Color = Grammar.GetMaximumSubtreeCount(rootNode.Symbol) == Grammar.GetMinimumSubtreeCount(rootNode.Symbol) ? Color.LightGray : Color.Black;
262          graphics.DrawString("+", font, pen.Brush, increaseMinimumSubtreeCountRectangle, stringFormat);
263          graphics.DrawRectangle(pen, Rectangle.Round(increaseMinimumSubtreeCountRectangle));
264          if (pen.Color == Color.LightGray) increaseMinimumSubtreeCountRectangle = RectangleF.Empty;
265
266          pen.Color = Grammar.GetMinimumSubtreeCount(rootNode.Symbol) == rootNode.Symbol.MinimumArity ? Color.LightGray : Color.Black;
267          graphics.DrawString("-", font, pen.Brush, decreaseMinimumSubtreeCountRectangle, stringFormat);
268          graphics.DrawRectangle(pen, Rectangle.Round(decreaseMinimumSubtreeCountRectangle));
269          if (pen.Color == Color.LightGray) decreaseMinimumSubtreeCountRectangle = RectangleF.Empty;
270
271          pen.Color = Grammar.GetMaximumSubtreeCount(rootNode.Symbol) == rootNode.Symbol.MaximumArity ? Color.LightGray : Color.Black;
272          graphics.DrawRectangle(pen, Rectangle.Round(increaseMaximumSubtreeCountRectangle));
273          graphics.DrawString("+", font, pen.Brush, increaseMaximumSubtreeCountRectangle, stringFormat);
274          if (pen.Color == Color.LightGray) increaseMaximumSubtreeCountRectangle = RectangleF.Empty;
275
276          pen.Color = Grammar.GetMaximumSubtreeCount(rootNode.Symbol) == Grammar.GetMinimumSubtreeCount(rootNode.Symbol) ? Color.LightGray : Color.Black;
277          graphics.DrawRectangle(pen, Rectangle.Round(decreaseMaximumSubtreeCountRectangle));
278          graphics.DrawString("-", font, pen.Brush, decreaseMaximumSubtreeCountRectangle, stringFormat);
279          if (pen.Color == Color.LightGray) decreaseMaximumSubtreeCountRectangle = RectangleF.Empty;
280        }
281      }
282    }
283
284    private void allowedChildSymbolsControl_MouseDown(object sender, MouseEventArgs e) {
285      if (Grammar == null) return;
286      if (symbolicExpressionTreeChart.Tree == null) return;
287
288      var pointF = new PointF(e.X, e.Y);
289      var rootSymbol = symbolicExpressionTreeChart.Tree.Root.Symbol;
290      int minimumSubtreeCount = Grammar.GetMinimumSubtreeCount(rootSymbol);
291      int maximumSubtreecount = Grammar.GetMaximumSubtreeCount(rootSymbol);
292
293      bool changed = true;
294      if (increaseMinimumSubtreeCountRectangle.Contains(pointF))
295        Grammar.SetSubtreeCount(rootSymbol, minimumSubtreeCount + 1, maximumSubtreecount);
296      else if (decreaseMinimumSubtreeCountRectangle.Contains(pointF))
297        Grammar.SetSubtreeCount(rootSymbol, minimumSubtreeCount - 1, maximumSubtreecount);
298      else if (increaseMaximumSubtreeCountRectangle.Contains(pointF))
299        Grammar.SetSubtreeCount(rootSymbol, minimumSubtreeCount, maximumSubtreecount + 1);
300      else if (decreaseMaximumSubtreeCountRectangle.Contains(pointF))
301        Grammar.SetSubtreeCount(rootSymbol, minimumSubtreeCount, maximumSubtreecount - 1);
302      else
303        changed = false;
304
305      if (changed) BuildAllowedChildSymbolsTree();
306    }
307    #endregion
308
309  }
310
311  [NonDiscoverableType]
312  internal class DummySymbol : Symbol {
313    private const int minimumArity = 1;
314    private const int maximumArity = byte.MaxValue;
315
316    public override int MinimumArity {
317      get { return minimumArity; }
318    }
319    public override int MaximumArity {
320      get { return maximumArity; }
321    }
322
323    public DummySymbol(DummySymbol original, Cloner cloner) : base(original, cloner) { }
324    public DummySymbol(string name) : base(name, "DummySymbol for views") { }
325    public override IDeepCloneable Clone(Cloner cloner) { return new DummySymbol(this, cloner); }
326  }
327}
Note: See TracBrowser for help on using the repository browser.