Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HL-3.2-MonoMigration/HeuristicLab.StructureIdentification/GPOperatorGroup.cs @ 640

Last change on this file since 640 was 529, checked in by gkronber, 16 years ago

fixed two loose ends from r525 (#263):

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