Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.StructureIdentification/GPOperatorGroup.cs @ 463

Last change on this file since 463 was 432, checked in by gkronber, 16 years ago
  • removed the button and methods for manual recalculation of min tree bounds introduced with r423 because it soon won't be needed anymore
  • GPOperatorGroup adds event-handlers to SubOperatorTypeConstraints on the operators added to the library to automatically update min tree size and height when any of them is changed.

(ticket #225)

File size: 8.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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.Linq;
25using System.Text;
26using HeuristicLab.Core;
27using HeuristicLab.Operators;
28using HeuristicLab.Data;
29using HeuristicLab.Random;
30using HeuristicLab.Constraints;
31
32namespace HeuristicLab.StructureIdentification {
33  public class GPOperatorGroup : OperatorGroup {
34    private Dictionary<IOperator, int> minTreeHeight = new Dictionary<IOperator, int>();
35    private Dictionary<IOperator, int> minTreeSize = new Dictionary<IOperator, int>();
36    private SubOperatorsConstraintAnalyser constraintAnalyser = new SubOperatorsConstraintAnalyser();
37
38    public GPOperatorGroup()
39      : base() {
40    }
41
42    public override void AddOperator(IOperator op) {
43      base.AddOperator(op);
44      var localVariableInfos = op.VariableInfos.Where(f => f.Local);
45
46      if(op.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT) == null) {
47        op.AddVariable(new Variable(GPOperatorLibrary.MIN_TREE_HEIGHT, new IntData(-1)));
48      }
49      if(op.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE) == null) {
50        op.AddVariable(new Variable(GPOperatorLibrary.MIN_TREE_SIZE, new IntData(-1)));
51      }
52      if(op.GetVariable(GPOperatorLibrary.TICKETS) == null) {
53        op.AddVariable(new Variable(GPOperatorLibrary.TICKETS, new DoubleData(1.0)));
54      }
55      foreach(IConstraint c in op.Constraints) {
56        if(c is SubOperatorTypeConstraint || c is AllSubOperatorsTypeConstraint) c.Changed += new EventHandler(UpdateTreeBounds);
57      }
58      OnOperatorAdded(op);
59    }
60
61    void UpdateTreeBounds(object sender, EventArgs e) {
62      RecalculateMinimalTreeBounds();
63    }
64
65    private void RecalculateMinimalTreeBounds() {
66      minTreeHeight.Clear();
67      minTreeSize.Clear();
68      constraintAnalyser.AllPossibleOperators = Operators;
69
70      foreach(IOperator op in Operators) {
71        ((IntData)op.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data = RecalculateMinimalTreeHeight(op);
72        ((IntData)op.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data = RecalculateMinimalTreeSize(op);
73      }
74    }
75
76    private int RecalculateMinimalTreeSize(IOperator op) {
77      // check for memoized value
78      if(minTreeSize.ContainsKey(op)) {
79        return minTreeSize[op];
80      }
81
82      int minArity;
83      int maxArity;
84      GetMinMaxArity(op, out minArity, out maxArity);
85      // no suboperators possible => minimalTreeSize == 1 (the current node)
86      if(minArity == 0 && maxArity == 0) {
87        minTreeSize[op] = 1;
88        return 1;
89      }
90
91      // when suboperators are necessary we have to find the smallest possible tree (recursively)
92      // the minimal size of the parent is 1 + the sum of the minimal sizes of all subtrees
93      int subTreeSizeSum = 0;
94
95      // mark the currently processed operator to prevent infinite recursions and stack overflow
96      minTreeSize[op] = 9999;
97      for(int i = 0; i < minArity; i++) {
98        // calculate the minTreeSize of all allowed sub-operators
99        // if the list of allowed suboperators is empty because the operator needs suboperators
100        // but there are no valid suboperators defined in the current group then we just use an impossible
101        // tree size here to indicate that there was a problem.
102        // usually as more operators are added to the group the problem will be corrected (by adding the missing operator).
103        // however if the missing operator is never added the high min tree size here has the effect that this operator
104        // will not be included in generated subtrees because the resulting size would always be higher than a reasonably set
105        // maximal tree size.
106        int minSubTreeSize = constraintAnalyser.GetAllowedOperators(op, i).Select(subOp => RecalculateMinimalTreeSize(subOp))
107          .Concat(Enumerable.Repeat(9999, 1)).Min();
108        subTreeSizeSum += minSubTreeSize;
109      }
110
111      minTreeSize[op] = subTreeSizeSum + 1;
112      return subTreeSizeSum + 1;
113    }
114
115    private int RecalculateMinimalTreeHeight(IOperator op) {
116      // check for memoized value
117      if(minTreeHeight.ContainsKey(op)) {
118        return minTreeHeight[op];
119      }
120
121      int minArity;
122      int maxArity;
123      GetMinMaxArity(op, out minArity, out maxArity);
124      // no suboperators possible => minimalTreeHeight == 1
125      if(minArity == 0 && maxArity == 0) {
126        minTreeHeight[op] = 1;
127        return 1;
128      }
129
130      // when suboperators are necessary we have to find the smallest possible tree (recursively)
131      // the minimal height of the parent is 1 + the height of the largest subtree
132      int maxSubTreeHeight = 0;
133
134      // mark the currently processed operator to prevent infinite recursions leading to stack overflow
135      minTreeHeight[op] = 9999;
136      for(int i = 0; i < minArity; i++) {
137        // calculate the minTreeHeight of all possible sub-operators.
138        // use the smallest possible subTree as lower bound for the subTreeHeight.
139        // if the list of allowed suboperators is empty because the operator needs suboperators
140        // but there are no valid suboperators defined in the current group then we use an impossible tree height
141        // to indicate that there was a problem.
142        // usually as more operators are added to the group the problem will be corrected (by adding the missing operator).
143        // however if the missing operator is never added the high min tree height here has the effect that this operator
144        // will not be included in generated subtrees because the resulting (virtual) height would always be higher than a reasonably set
145        // maximal tree height.
146        int minSubTreeHeight = constraintAnalyser.GetAllowedOperators(op, i).Select(subOp => RecalculateMinimalTreeHeight(subOp))
147          .Concat(Enumerable.Repeat(9999, 1)).Min();
148
149        // if the smallest height of this subtree is larger than all other subtrees before we have to update the min height of the parent
150        if(minSubTreeHeight > maxSubTreeHeight) {
151          maxSubTreeHeight = minSubTreeHeight;
152        }
153      }
154
155      minTreeHeight[op] = maxSubTreeHeight + 1;
156      return maxSubTreeHeight + 1;
157    }
158
159    private void GetMinMaxArity(IOperator op, out int minArity, out int maxArity) {
160      foreach(IConstraint constraint in op.Constraints) {
161        NumberOfSubOperatorsConstraint theConstraint = constraint as NumberOfSubOperatorsConstraint;
162        if(theConstraint != null) {
163          minArity = theConstraint.MinOperators.Data;
164          maxArity = theConstraint.MaxOperators.Data;
165          return;
166        }
167      }
168      // the default arity is 2
169      minArity = 2;
170      maxArity = 2;
171    }
172
173    public override void AddSubGroup(IOperatorGroup group) {
174      throw new NotSupportedException();
175    }
176
177    public override void RemoveOperator(IOperator op) {
178      base.RemoveOperator(op);
179      op.RemoveVariable(GPOperatorLibrary.MIN_TREE_SIZE);
180      op.RemoveVariable(GPOperatorLibrary.MIN_TREE_HEIGHT);
181      op.RemoveVariable(GPOperatorLibrary.TICKETS);
182      foreach(IConstraint c in op.Constraints) {
183        if(c is SubOperatorTypeConstraint || c is AllSubOperatorsTypeConstraint) c.Changed -= new EventHandler(UpdateTreeBounds);
184      }
185      OnOperatorRemoved(op);
186    }
187
188    public override void RemoveSubGroup(IOperatorGroup group) {
189      throw new NotSupportedException();
190    }
191
192    public event EventHandler OperatorAdded;
193    public event EventHandler OperatorRemoved;
194
195    protected virtual void OnOperatorAdded(IOperator op) {
196      if(OperatorAdded != null) {
197        OperatorAdded(this, new OperatorEventArgs(op));
198      }
199    }
200    protected virtual void OnOperatorRemoved(IOperator op) {
201      if(OperatorRemoved != null) {
202        OperatorRemoved(this, new OperatorEventArgs(op));
203      }
204    }
205  }
206
207  internal class OperatorEventArgs : EventArgs {
208    public IOperator op;
209
210    public OperatorEventArgs(IOperator op) {
211      this.op = op;
212    }
213  }
214}
Note: See TracBrowser for help on using the repository browser.