Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 237 was 186, checked in by gkronber, 16 years ago

addressed #123 by changing the default manipulation operator to NormalRandomAdder, full fix not possible.

File size: 13.0 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    public GPOperatorGroup()
35      : base() {
36    }
37
38    public override void AddOperator(IOperator op) {
39      base.AddOperator(op);
40
41      var localVariableInfos = op.VariableInfos.Where(f => f.Local);
42
43      if(op.GetVariable(GPOperatorLibrary.MANIPULATION) == null) {
44        CombinedOperator manipulationOperator = new CombinedOperator();
45        SequentialProcessor manipulationSequence = new SequentialProcessor();
46        foreach(IVariableInfo variableInfo in localVariableInfos) {
47          IOperator manipulator = GetDefaultManipulationOperator(variableInfo);
48          if (manipulator != null) {
49            manipulationSequence.AddSubOperator(manipulator);
50          }
51        }
52        if(manipulationSequence.SubOperators.Count > 0) {
53          op.AddVariable(new Variable(GPOperatorLibrary.MANIPULATION, manipulationOperator));
54
55          manipulationOperator.OperatorGraph.AddOperator(manipulationSequence);
56          manipulationOperator.OperatorGraph.InitialOperator = manipulationSequence;
57          foreach(IOperator subOp in manipulationSequence.SubOperators) {
58            manipulationOperator.OperatorGraph.AddOperator(subOp);
59          }
60        }
61      }
62
63      if(op.GetVariable(GPOperatorLibrary.INITIALIZATION) == null) {
64        CombinedOperator initOperator = new CombinedOperator();
65        SequentialProcessor initSequence = new SequentialProcessor();
66        foreach(IVariableInfo variableInfo in localVariableInfos) {
67          IOperator initializer = GetDefaultInitOperator(variableInfo);
68          if (initializer != null) {
69            initSequence.AddSubOperator(initializer);
70          }
71        }
72        if(initSequence.SubOperators.Count > 0) {
73          op.AddVariable(new Variable(GPOperatorLibrary.INITIALIZATION, initOperator));
74          initOperator.OperatorGraph.AddOperator(initSequence);
75          initOperator.OperatorGraph.InitialOperator = initSequence;
76          foreach(IOperator subOp in initSequence.SubOperators) {
77            initOperator.OperatorGraph.AddOperator(subOp);
78          }
79        }
80      }
81
82      // add a new typeid if necessary
83      if(op.GetVariable(GPOperatorLibrary.TYPE_ID) == null) {
84        op.AddVariable(new Variable(GPOperatorLibrary.TYPE_ID, new StringData(Guid.NewGuid().ToString())));
85      }
86
87      if(op.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT) == null) {
88        op.AddVariable(new Variable(GPOperatorLibrary.MIN_TREE_HEIGHT, new IntData(-1)));
89      }
90      if(op.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE) == null) {
91        op.AddVariable(new Variable(GPOperatorLibrary.MIN_TREE_SIZE, new IntData(-1)));
92      }
93      if(op.GetVariable(GPOperatorLibrary.ALLOWED_SUBOPERATORS) == null) {
94        op.AddVariable(new Variable(GPOperatorLibrary.ALLOWED_SUBOPERATORS, new ItemList()));
95      }
96      if(op.GetVariable(GPOperatorLibrary.TICKETS) == null) {
97        op.AddVariable(new Variable(GPOperatorLibrary.TICKETS, new DoubleData(1.0)));
98      }
99
100      RecalculateAllowedSuboperators();
101      RecalculateMinimalTreeBounds();
102
103      OnOperatorAdded(op);
104    }
105
106
107    private Dictionary<string, int> minTreeHeight = new Dictionary<string, int>();
108    private Dictionary<string, int> minTreeSize = new Dictionary<string, int>();
109    private SubOperatorsConstraintAnalyser constraintAnalyser = new SubOperatorsConstraintAnalyser();
110
111    private void RecalculateAllowedSuboperators() {
112      foreach(IOperator op in Operators) {
113        RecalculateAllowedSuboperators(op);
114      }
115    }
116
117    private void RecalculateAllowedSuboperators(IOperator op) {
118      constraintAnalyser.AllPossibleOperators = Operators;
119      int minArity;
120      int maxArity;
121      GetMinMaxArity(op, out minArity, out maxArity);
122      var slotsList = (ItemList)op.GetVariable(GPOperatorLibrary.ALLOWED_SUBOPERATORS).Value;
123      slotsList.Clear();
124      for(int i = 0; i < maxArity; i++) {
125        ItemList slotList = new ItemList();
126        foreach(IOperator allowedOp in constraintAnalyser.GetAllowedOperators(op, i)) {
127          slotList.Add(allowedOp);
128        }
129        slotsList.Add(slotList);
130      }
131    }
132
133
134    private void RecalculateMinimalTreeBounds() {
135      minTreeHeight.Clear();
136      minTreeSize.Clear();
137      constraintAnalyser.AllPossibleOperators = Operators;
138
139      foreach(IOperator op in Operators) {
140        ((IntData)op.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data = RecalculateMinimalTreeHeight(op);
141        ((IntData)op.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data = RecalculateMinimalTreeSize(op);
142      }
143    }
144
145    private int RecalculateMinimalTreeSize(IOperator op) {
146      string typeId = GetTypeId(op);
147      // check for memoized value
148      if(minTreeSize.ContainsKey(typeId)) {
149        return minTreeSize[typeId];
150      }
151
152      int minArity;
153      int maxArity;
154      GetMinMaxArity(op, out minArity, out maxArity);
155      // no suboperators possible => minimalTreeSize == 1 (the current node)
156      if(minArity == 0 && maxArity == 0) {
157        minTreeSize[typeId] = 1;
158        return 1;
159      }
160
161      // when suboperators are necessary we have to find the smallest possible tree (recursively)
162      // the minimal size of the parent is 1 + the sum of the minimal sizes of all subtrees
163      int subTreeSizeSum = 0;
164
165      // mark the currently processed operator to prevent infinite recursions and stack overflow
166      minTreeSize[typeId] = 9999;
167      for(int i = 0; i < minArity; i++) {
168        // calculate the minTreeSize of all allowed sub-operators
169        // if the list of allowed suboperators is empty because the operator needs suboperators
170        // but there are no valid suboperators defined in the current group then we just use an impossible
171        // tree size here to indicate that there was a problem.
172        // usually as more operators are added to the group the problem will be corrected (by adding the missing operator).
173        // however if the missing operator is never added the high min tree size here has the effect that this operator
174        // will not be included in generated subtrees because the resulting size would always be higher than a reasonably set
175        // maximal tree size.
176        int minSubTreeSize = constraintAnalyser.GetAllowedOperators(op, i).Select(subOp => RecalculateMinimalTreeSize(subOp))
177          .Concat(Enumerable.Repeat(9999, 1)).Min();
178        subTreeSizeSum += minSubTreeSize;
179      }
180
181      minTreeSize[typeId] = subTreeSizeSum + 1;
182      return subTreeSizeSum + 1;
183    }
184
185
186    private int RecalculateMinimalTreeHeight(IOperator op) {
187      string typeId = GetTypeId(op);
188      // check for memoized value
189      if(minTreeHeight.ContainsKey(typeId)) {
190        return minTreeHeight[typeId];
191      }
192
193      int minArity;
194      int maxArity;
195      GetMinMaxArity(op, out minArity, out maxArity);
196      // no suboperators possible => minimalTreeHeight == 1
197      if(minArity == 0 && maxArity == 0) {
198        minTreeHeight[typeId] = 1;
199        return 1;
200      }
201
202      // when suboperators are necessary we have to find the smallest possible tree (recursively)
203      // the minimal height of the parent is 1 + the height of the largest subtree
204      int maxSubTreeHeight = 0;
205
206      // mark the currently processed operator to prevent infinite recursions leading to stack overflow
207      minTreeHeight[typeId] = 9999;
208      for(int i = 0; i < minArity; i++) {
209        // calculate the minTreeHeight of all possible sub-operators.
210        // use the smallest possible subTree as lower bound for the subTreeHeight.
211        // if the list of allowed suboperators is empty because the operator needs suboperators
212        // but there are no valid suboperators defined in the current group then we use an impossible tree height
213        // to indicate that there was a problem.
214        // usually as more operators are added to the group the problem will be corrected (by adding the missing operator).
215        // however if the missing operator is never added the high min tree height here has the effect that this operator
216        // will not be included in generated subtrees because the resulting (virtual) height would always be higher than a reasonably set
217        // maximal tree height.
218        int minSubTreeHeight = constraintAnalyser.GetAllowedOperators(op, i).Select(subOp => RecalculateMinimalTreeHeight(subOp))
219          .Concat(Enumerable.Repeat(9999, 1)).Min();
220
221        // if the smallest height of this subtree is larger than all other subtrees before we have to update the min height of the parent
222        if(minSubTreeHeight > maxSubTreeHeight) {
223          maxSubTreeHeight = minSubTreeHeight;
224        }
225      }
226
227      minTreeHeight[typeId] = maxSubTreeHeight + 1;
228      return maxSubTreeHeight + 1;
229    }
230
231    private void GetMinMaxArity(IOperator op, out int minArity, out int maxArity) {
232      foreach(IConstraint constraint in op.Constraints) {
233        NumberOfSubOperatorsConstraint theConstraint = constraint as NumberOfSubOperatorsConstraint;
234        if(theConstraint != null) {
235          minArity = theConstraint.MinOperators.Data;
236          maxArity = theConstraint.MaxOperators.Data;
237          return;
238        }
239      }
240      // the default arity is 2
241      minArity = 2;
242      maxArity = 2;
243    }
244
245    private string GetTypeId(IOperator op) {
246      return ((StringData)op.GetVariable(GPOperatorLibrary.TYPE_ID).Value).Data;
247    }
248
249
250    private IOperator GetDefaultManipulationOperator(IVariableInfo variableInfo) {
251      IOperator shaker;
252      if(variableInfo.DataType == typeof(ConstrainedDoubleData) ||
253        variableInfo.DataType == typeof(ConstrainedIntData) ||
254        variableInfo.DataType == typeof(DoubleData) ||
255        variableInfo.DataType == typeof(IntData)) {
256        shaker = new NormalRandomAdder();
257      } else {
258        return null;
259      }
260      shaker.GetVariableInfo("Value").ActualName = variableInfo.FormalName;
261      shaker.Name = variableInfo.FormalName + " manipulation";
262      return shaker;
263    }
264
265    private IOperator GetDefaultInitOperator(IVariableInfo variableInfo) {
266      IOperator shaker;
267      if(variableInfo.DataType == typeof(ConstrainedDoubleData) ||
268        variableInfo.DataType == typeof(ConstrainedIntData) ||
269        variableInfo.DataType == typeof(DoubleData) ||
270        variableInfo.DataType == typeof(IntData)) {
271        shaker = new UniformRandomizer();
272      } else {
273        return null;
274      }
275      shaker.GetVariableInfo("Value").ActualName = variableInfo.FormalName;
276      shaker.Name = variableInfo.FormalName + " initialization";
277      return shaker;
278    }
279
280    public override void AddSubGroup(IOperatorGroup group) {
281      throw new NotSupportedException();
282    }
283
284    public override void RemoveOperator(IOperator op) {
285      base.RemoveOperator(op);
286      op.RemoveVariable(GPOperatorLibrary.MANIPULATION);
287      op.RemoveVariable(GPOperatorLibrary.INITIALIZATION);
288      op.RemoveVariable(GPOperatorLibrary.TYPE_ID);
289      op.RemoveVariable(GPOperatorLibrary.MIN_TREE_SIZE);
290      op.RemoveVariable(GPOperatorLibrary.MIN_TREE_HEIGHT);
291      op.RemoveVariable(GPOperatorLibrary.ALLOWED_SUBOPERATORS);
292      op.RemoveVariable(GPOperatorLibrary.TICKETS);
293
294      OnOperatorRemoved(op);
295    }
296
297    public override void RemoveSubGroup(IOperatorGroup group) {
298      throw new NotSupportedException();
299    }
300
301    public event EventHandler OperatorAdded;
302    public event EventHandler OperatorRemoved;
303
304    protected virtual void OnOperatorAdded(IOperator op) {
305      if(OperatorAdded != null) {
306        OperatorAdded(this, new OperatorEventArgs(op));
307      }
308    }
309    protected virtual void OnOperatorRemoved(IOperator op) {
310      if(OperatorRemoved != null) {
311        OperatorRemoved(this, new OperatorEventArgs(op));
312      }
313    }
314  }
315
316
317  internal class OperatorEventArgs : EventArgs {
318    public IOperator op;
319
320    public OperatorEventArgs(IOperator op) {
321      this.op = op;
322    }
323  }
324}
Note: See TracBrowser for help on using the repository browser.