Free cookie consent management tool by TermsFeed Policy Generator

source: branches/DataPreprocessing/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs @ 10538

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