Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Persistence Test/HeuristicLab.GP/3.4/GPOperatorGroup.cs @ 3581

Last change on this file since 3581 was 2474, checked in by swagner, 15 years ago

Implemented generic EventArgs (#796)

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