Changeset 180
- Timestamp:
- 04/24/08 14:29:31 (17 years ago)
- Location:
- trunk/sources/HeuristicLab.StructureIdentification
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.StructureIdentification/Manipulation/ChangeNodeTypeManipulation.cs
r167 r180 128 128 129 129 private IFunctionTree ChangeTerminalType(IFunctionTree parent, IFunctionTree child, int childIndex, TreeGardener gardener, MersenneTwister random) { 130 IList<IFunction> allowed Children;130 IList<IFunction> allowedTerminals; 131 131 if (parent == null) { 132 allowed Children= gardener.Terminals;132 allowedTerminals = gardener.Terminals; 133 133 } else { 134 allowed Children= new List<IFunction>();134 allowedTerminals = new List<IFunction>(); 135 135 var allAllowedChildren = gardener.GetAllowedSubFunctions(parent.Function, childIndex); 136 136 foreach(IFunction c in allAllowedChildren) { 137 if(gardener.IsTerminal(c)) allowed Children.Add(c);137 if(gardener.IsTerminal(c)) allowedTerminals.Add(c); 138 138 } 139 139 } 140 140 // selecting from the terminals should always work since the current child was also a terminal 141 141 // so in the worst case we will just create a new terminal of the same type again. 142 return gardener.CreateRandomTree(allowed Children[random.Next(allowedChildren.Count)], 1, 1, false);142 return gardener.CreateRandomTree(allowedTerminals, 1, 1); 143 143 } 144 144 -
trunk/sources/HeuristicLab.StructureIdentification/TreeGardener.cs
r179 r180 50 50 } 51 51 52 #region constructors 52 53 internal TreeGardener(IRandom random, GPOperatorLibrary funLibrary) { 53 54 this.random = random; … … 69 70 } 70 71 } 72 #endregion 71 73 72 74 #region random initialization 75 /// <summary> 76 /// Creates a random balanced tree with a maximal size and height. When the max-height or max-size are 1 it will return a random terminal. 77 /// In other cases it will return either a terminal (tree of size 1) or any other tree with a function in it's root (at least height 2). 78 /// </summary> 79 /// <param name="maxTreeSize">Maximal size of the tree (number of nodes).</param> 80 /// <param name="maxTreeHeight">Maximal height of the tree.</param> 81 /// <returns></returns> 73 82 internal IFunctionTree CreateBalancedRandomTree(int maxTreeSize, int maxTreeHeight) { 83 IFunctionTree root = CreateRandomRoot(maxTreeSize, maxTreeHeight); 84 MakeBalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 85 return root; 86 } 87 88 /// <summary> 89 /// Creates a random (unbalanced) tree with a maximal size and height. When the max-height or max-size are 1 it will return a random terminal. 90 /// In other cases it will return either a terminal (tree of size 1) or any other tree with a function in it's root (at least height 2). 91 /// </summary> 92 /// <param name="maxTreeSize">Maximal size of the tree (number of nodes).</param> 93 /// <param name="maxTreeHeight">Maximal height of the tree.</param> 94 /// <returns></returns> 95 internal IFunctionTree CreateUnbalancedRandomTree(int maxTreeSize, int maxTreeHeight) { 96 IFunctionTree root = CreateRandomRoot(maxTreeSize, maxTreeHeight); 97 MakeUnbalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 98 return root; 99 } 100 101 /// <summary> 102 /// selects a random function from allowedFunctions and creates a random (unbalanced) tree with maximal size and height. 103 /// </summary> 104 /// <param name="allowedFunctions">Set of allowed functions.</param> 105 /// <param name="maxTreeSize">Maximal size of the tree (number of nodes).</param> 106 /// <param name="maxTreeHeight">Maximal height of the tree.</param> 107 /// <returns>New random unbalanced tree</returns> 108 internal IFunctionTree CreateRandomTree(ICollection<IFunction> allowedFunctions, int maxTreeSize, int maxTreeHeight) { 109 // default is non-balanced trees 110 return CreateRandomTree(allowedFunctions, maxTreeSize, maxTreeHeight, false); 111 } 112 113 /// <summary> 114 /// selects a random function from allowedFunctions and creates a (un)balanced random tree with maximal size and height. 115 /// </summary> 116 /// <param name="allowedFunctions">Set of allowed functions.</param> 117 /// <param name="maxTreeSize">Maximal size of the tree (number of nodes).</param> 118 /// <param name="maxTreeHeight">Maximal height of the tree.</param> 119 /// <param name="balanceTrees">Flag determining whether the tree should be balanced or not.</param> 120 /// <returns>New random tree</returns> 121 internal IFunctionTree CreateRandomTree(ICollection<IFunction> allowedFunctions, int maxTreeSize, int maxTreeHeight, bool balanceTrees) { 122 int minTreeHeight = allowedFunctions.Select(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data).Min(); 123 if(minTreeHeight > maxTreeHeight) 124 maxTreeHeight = minTreeHeight; 125 126 int minTreeSize = allowedFunctions.Select(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data).Min(); 127 if(minTreeSize > maxTreeSize) 128 maxTreeSize = minTreeSize; 129 130 int treeHeight = random.Next(minTreeHeight, maxTreeHeight + 1); 131 int treeSize = random.Next(minTreeSize, maxTreeSize + 1); 132 133 IFunction[] possibleFunctions = allowedFunctions.Where(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data <= treeHeight && 134 ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data <= treeSize).ToArray(); 135 IFunction selectedFunction = possibleFunctions[random.Next(possibleFunctions.Length)]; 136 137 IFunctionTree root = new FunctionTree(selectedFunction); 138 if(balanceTrees) { 139 MakeBalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 140 } else { 141 MakeUnbalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 142 } 143 return root; 144 } 145 146 internal CompositeOperation CreateInitializationOperation(ICollection<IFunctionTree> trees, IScope scope) { 147 // needed for the parameter shaking operation 148 CompositeOperation initializationOperation = new CompositeOperation(); 149 Scope tempScope = new Scope("Temp. initialization scope"); 150 151 var parametricTrees = trees.Where(t => t.Function.GetVariable(GPOperatorLibrary.INITIALIZATION) != null); 152 foreach(IFunctionTree tree in parametricTrees) { 153 // enqueue an initialization operation for each operator with local variables 154 IOperator initialization = (IOperator)tree.Function.GetVariable(GPOperatorLibrary.INITIALIZATION).Value; 155 Scope initScope = new Scope(); 156 // copy the local variables into a temporary scope used for initialization 157 foreach(IVariable variable in tree.LocalVariables) { 158 initScope.AddVariable(variable); 159 } 160 tempScope.AddSubScope(initScope); 161 initializationOperation.AddOperation(new AtomicOperation(initialization, initScope)); 162 } 163 Scope backupScope = new Scope("backup"); 164 foreach(Scope subScope in scope.SubScopes) { 165 backupScope.AddSubScope(subScope); 166 } 167 scope.AddSubScope(tempScope); 168 scope.AddSubScope(backupScope); 169 // add an operation to remove the temporary scopes 170 initializationOperation.AddOperation(new AtomicOperation(new RightReducer(), scope)); 171 return initializationOperation; 172 } 173 #endregion 174 175 #region tree information gathering 176 internal int GetTreeSize(IFunctionTree tree) { 177 return 1 + tree.SubTrees.Sum(f => GetTreeSize(f)); 178 } 179 180 internal int GetTreeHeight(IFunctionTree tree) { 181 if(tree.SubTrees.Count == 0) return 1; 182 return 1 + tree.SubTrees.Max(f => GetTreeHeight(f)); 183 } 184 185 internal IFunctionTree GetRandomParentNode(IFunctionTree tree) { 186 List<IFunctionTree> parentNodes = new List<IFunctionTree>(); 187 188 // add null for the parent of the root node 189 parentNodes.Add(null); 190 191 TreeForEach(tree, delegate(IFunctionTree possibleParentNode) { 192 if(possibleParentNode.SubTrees.Count > 0) { 193 parentNodes.Add(possibleParentNode); 194 } 195 }); 196 197 return parentNodes[random.Next(parentNodes.Count)]; 198 } 199 200 internal ICollection<IFunctionTree> GetAllSubTrees(IFunctionTree root) { 201 List<IFunctionTree> allTrees = new List<IFunctionTree>(); 202 TreeForEach(root, t => { allTrees.Add(t); }); 203 return allTrees; 204 } 205 206 /// <summary> 207 /// returns the height level of branch in the tree 208 /// if the branch == tree => 1 209 /// if branch is in the sub-trees of tree => 2 210 /// ... 211 /// if branch is not found => -1 212 /// </summary> 213 /// <param name="tree">root of the function tree to process</param> 214 /// <param name="branch">branch that is searched in the tree</param> 215 /// <returns></returns> 216 internal int GetBranchLevel(IFunctionTree tree, IFunctionTree branch) { 217 return GetBranchLevelHelper(tree, branch, 1); 218 } 219 220 // 'tail-recursive' helper 221 private int GetBranchLevelHelper(IFunctionTree tree, IFunctionTree branch, int level) { 222 if(branch == tree) return level; 223 224 foreach(IFunctionTree subTree in tree.SubTrees) { 225 int result = GetBranchLevelHelper(subTree, branch, level + 1); 226 if(result != -1) return result; 227 } 228 229 return -1; 230 } 231 232 internal bool IsValidTree(IFunctionTree tree) { 233 foreach(IConstraint constraint in tree.Function.Constraints) { 234 if(constraint is NumberOfSubOperatorsConstraint) { 235 int max = ((NumberOfSubOperatorsConstraint)constraint).MaxOperators.Data; 236 int min = ((NumberOfSubOperatorsConstraint)constraint).MinOperators.Data; 237 if(tree.SubTrees.Count < min || tree.SubTrees.Count > max) 238 return false; 239 } 240 } 241 foreach(IFunctionTree subTree in tree.SubTrees) { 242 if(!IsValidTree(subTree)) return false; 243 } 244 return true; 245 } 246 247 // returns a random branch from the specified level in the tree 248 internal IFunctionTree GetRandomBranch(IFunctionTree tree, int level) { 249 if(level == 0) return tree; 250 List<IFunctionTree> branches = GetBranchesAtLevel(tree, level); 251 return branches[random.Next(branches.Count)]; 252 } 253 #endregion 254 255 #region function information (arity, allowed childs and parents) 256 internal ICollection<IFunction> GetPossibleParents(List<IFunction> list) { 257 List<IFunction> result = new List<IFunction>(); 258 foreach(IFunction f in functions) { 259 if(IsPossibleParent(f, list)) { 260 result.Add(f); 261 } 262 } 263 return result; 264 } 265 266 private bool IsPossibleParent(IFunction f, List<IFunction> children) { 267 int minArity; 268 int maxArity; 269 GetMinMaxArity(f, out minArity, out maxArity); 270 271 // note: we can't assume that the operators in the children list have different types! 272 273 // when the maxArity of this function is smaller than the list of operators that 274 // should be included as sub-operators then it can't be a parent 275 if(maxArity < children.Count()) { 276 return false; 277 } 278 int nSlots = Math.Max(minArity, children.Count); 279 280 SubOperatorsConstraintAnalyser analyzer = new SubOperatorsConstraintAnalyser(); 281 analyzer.AllPossibleOperators = children.Cast<IOperator>().ToArray<IOperator>(); 282 283 List<HashSet<IFunction>> slotSets = new List<HashSet<IFunction>>(); 284 285 // we iterate through all slots for sub-trees and calculate the set of 286 // allowed functions for this slot. 287 // we only count those slots that can hold at least one of the children that we should combine 288 for(int slot = 0; slot < nSlots; slot++) { 289 HashSet<IFunction> functionSet = new HashSet<IFunction>(analyzer.GetAllowedOperators(f, slot).Cast<IFunction>()); 290 if(functionSet.Count() > 0) { 291 slotSets.Add(functionSet); 292 } 293 } 294 295 // ok at the end of this operation we know how many slots of the parent can actually 296 // hold one of our children. 297 // if the number of slots is smaller than the number of children we can be sure that 298 // we can never combine all children as sub-trees of the function and thus the function 299 // can't be a parent. 300 if(slotSets.Count() < children.Count()) { 301 return false; 302 } 303 304 // finally we sort the sets by size and beginning from the first set select one 305 // function for the slot and thus remove it as possible sub-tree from the remaining sets. 306 // when we can successfully assign all available children to a slot the function is a valid parent 307 // when only a subset of all children can be assigned to slots the function is no valid parent 308 slotSets.Sort((p, q) => p.Count() - q.Count()); 309 310 int assignments = 0; 311 for(int i = 0; i < slotSets.Count() - 1; i++) { 312 if(slotSets[i].Count > 0) { 313 IFunction selected = slotSets[i].ElementAt(0); 314 assignments++; 315 for(int j = i + 1; j < slotSets.Count(); j++) { 316 slotSets[j].Remove(selected); 317 } 318 } 319 } 320 321 // sanity check 322 if(assignments > children.Count) throw new InvalidProgramException(); 323 return assignments == children.Count - 1; 324 } 325 internal IList<IFunction> GetAllowedParents(IFunction child, int childIndex) { 326 List<IFunction> parents = new List<IFunction>(); 327 foreach(IFunction function in functions) { 328 ICollection<IFunction> allowedSubFunctions = GetAllowedSubFunctions(function, childIndex); 329 if(allowedSubFunctions.Contains(child)) { 330 parents.Add(function); 331 } 332 } 333 return parents; 334 } 335 internal bool IsTerminal(IFunction f) { 336 int minArity; 337 int maxArity; 338 GetMinMaxArity(f, out minArity, out maxArity); 339 return minArity == 0 && maxArity == 0; 340 } 341 internal IList<IFunction> GetAllowedSubFunctions(IFunction f, int index) { 342 if(f == null) { 343 return allFunctions; 344 } else { 345 ItemList slotList = (ItemList)f.GetVariable(GPOperatorLibrary.ALLOWED_SUBOPERATORS).Value; 346 List<IFunction> result = new List<IFunction>(); 347 foreach(IFunction function in (ItemList)slotList[index]) { 348 result.Add(function); 349 } 350 return result; 351 } 352 } 353 internal void GetMinMaxArity(IFunction f, out int minArity, out int maxArity) { 354 foreach(IConstraint constraint in f.Constraints) { 355 NumberOfSubOperatorsConstraint theConstraint = constraint as NumberOfSubOperatorsConstraint; 356 if(theConstraint != null) { 357 minArity = theConstraint.MinOperators.Data; 358 maxArity = theConstraint.MaxOperators.Data; 359 return; 360 } 361 } 362 // the default arity is 2 363 minArity = 2; 364 maxArity = 2; 365 } 366 #endregion 367 368 #region private utility methods 369 private IFunctionTree CreateRandomRoot(int maxTreeSize, int maxTreeHeight) { 74 370 if(maxTreeHeight == 1 || maxTreeSize == 1) { 75 371 IFunction selectedTerminal = terminals[random.Next(terminals.Count())]; 76 372 return new FunctionTree(selectedTerminal); 77 373 } else { 78 IFunction[] possibleFunctions = functions.Where(f => GetMinimalTreeHeight(f) <= maxTreeHeight &&374 IFunction[] possibleFunctions = allFunctions.Where(f => GetMinimalTreeHeight(f) <= maxTreeHeight && 79 375 GetMinimalTreeSize(f) <= maxTreeSize).ToArray(); 80 376 IFunction selectedFunction = possibleFunctions[random.Next(possibleFunctions.Length)]; 81 FunctionTree root = new FunctionTree(selectedFunction); 82 MakeBalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 83 return root; 84 } 85 } 86 87 internal IFunctionTree CreateUnbalancedRandomTree(int maxTreeSize, int maxTreeHeight) { 88 IFunction[] possibleFunctions = allFunctions.Where(f => GetMinimalTreeHeight(f) <= maxTreeHeight && 89 GetMinimalTreeSize(f) <= maxTreeSize).ToArray(); 90 IFunction selectedFunction = possibleFunctions[random.Next(possibleFunctions.Length)]; 91 FunctionTree root = new FunctionTree(selectedFunction); 92 MakeUnbalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 93 return root; 94 } 95 96 internal IFunctionTree CreateRandomTree(ICollection<IFunction> allowedFunctions, int maxTreeSize, int maxTreeHeight) { 97 // default is non-balanced trees 98 return CreateRandomTree(allowedFunctions, maxTreeSize, maxTreeHeight, false); 99 } 100 101 internal IFunctionTree CreateRandomTree(ICollection<IFunction> allowedFunctions, int maxTreeSize, int maxTreeHeight, bool balanceTrees) { 102 103 int minTreeHeight = allowedFunctions.Select(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data).Min(); 104 if(minTreeHeight > maxTreeHeight) 105 maxTreeHeight = minTreeHeight; 106 107 int minTreeSize = allowedFunctions.Select(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data).Min(); 108 if(minTreeSize > maxTreeSize) 109 maxTreeSize = minTreeSize; 110 111 int treeHeight = random.Next(minTreeHeight, maxTreeHeight + 1); 112 int treeSize = random.Next(minTreeSize, maxTreeSize + 1); 113 114 IFunction[] possibleFunctions = allowedFunctions.Where(f => ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data <= treeHeight && 115 ((IntData)f.GetVariable(GPOperatorLibrary.MIN_TREE_SIZE).Value).Data <= treeSize).ToArray(); 116 IFunction selectedFunction = possibleFunctions[random.Next(possibleFunctions.Length)]; 117 118 return CreateRandomTree(selectedFunction, treeSize, treeHeight, balanceTrees); 119 } 120 121 internal IFunctionTree CreateRandomTree(IFunction rootFunction, int maxTreeSize, int maxTreeHeight, bool balanceTrees) { 122 IFunctionTree root = new FunctionTree(rootFunction); 123 if(balanceTrees) { 124 MakeBalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 125 } else { 126 MakeUnbalancedTree(root, maxTreeSize - 1, maxTreeHeight - 1); 127 } 128 if(GetTreeSize(root) > maxTreeSize || 129 GetTreeHeight(root) > maxTreeHeight) { 130 throw new InvalidProgramException(); 131 } 132 return root; 377 return new FunctionTree(selectedFunction); 378 } 133 379 } 134 380 … … 158 404 // types of possible sub-functions which can indirectly impose a limit for the depth of a given sub-tree 159 405 private void MakeBalancedTree(IFunctionTree parent, int maxTreeSize, int maxTreeHeight) { 160 if(maxTreeHeight == 0 || maxTreeSize == 0) return; // should never happen anyway406 if(maxTreeHeight == 0 || maxTreeSize == 0) return; 161 407 int minArity; 162 408 int maxArity; … … 191 437 } 192 438 193 internal CompositeOperation CreateInitializationOperation(ICollection<IFunctionTree> trees, IScope scope) {194 // needed for the parameter shaking operation195 CompositeOperation initializationOperation = new CompositeOperation();196 Scope tempScope = new Scope("Temp. initialization scope");197 198 var parametricTrees = trees.Where(t => t.Function.GetVariable(GPOperatorLibrary.INITIALIZATION) != null);199 200 foreach(IFunctionTree tree in parametricTrees) {201 // enqueue an initialization operation for each operator with local variables202 IOperator initialization = (IOperator)tree.Function.GetVariable(GPOperatorLibrary.INITIALIZATION).Value;203 Scope initScope = new Scope();204 205 // copy the local variables into a temporary scope used for initialization206 foreach(IVariable variable in tree.LocalVariables) {207 initScope.AddVariable(variable);208 }209 210 tempScope.AddSubScope(initScope);211 initializationOperation.AddOperation(new AtomicOperation(initialization, initScope));212 }213 214 Scope backupScope = new Scope("backup");215 foreach(Scope subScope in scope.SubScopes) {216 backupScope.AddSubScope(subScope);217 }218 219 scope.AddSubScope(tempScope);220 scope.AddSubScope(backupScope);221 222 // add an operation to remove the temporary scopes223 initializationOperation.AddOperation(new AtomicOperation(new RightReducer(), scope));224 return initializationOperation;225 }226 #endregion227 228 #region tree information gathering229 internal int GetTreeSize(IFunctionTree tree) {230 return 1 + tree.SubTrees.Sum(f => GetTreeSize(f));231 }232 233 internal int GetTreeHeight(IFunctionTree tree) {234 if(tree.SubTrees.Count == 0) return 1;235 return 1 + tree.SubTrees.Max(f => GetTreeHeight(f));236 }237 238 internal IFunctionTree GetRandomParentNode(IFunctionTree tree) {239 List<IFunctionTree> parentNodes = new List<IFunctionTree>();240 241 // add null for the parent of the root node242 parentNodes.Add(null);243 244 TreeForEach(tree, delegate(IFunctionTree possibleParentNode) {245 if(possibleParentNode.SubTrees.Count > 0) {246 parentNodes.Add(possibleParentNode);247 }248 });249 250 return parentNodes[random.Next(parentNodes.Count)];251 }252 253 internal ICollection<IFunctionTree> GetAllSubTrees(IFunctionTree root) {254 List<IFunctionTree> allTrees = new List<IFunctionTree>();255 TreeForEach(root, t => { allTrees.Add(t); });256 return allTrees;257 }258 259 /// <summary>260 /// returns the height level of branch in the tree261 /// if the branch == tree => 1262 /// if branch is in the sub-trees of tree => 2263 /// ...264 /// if branch is not found => -1265 /// </summary>266 /// <param name="tree">root of the function tree to process</param>267 /// <param name="branch">branch that is searched in the tree</param>268 /// <returns></returns>269 internal int GetBranchLevel(IFunctionTree tree, IFunctionTree branch) {270 return GetBranchLevelHelper(tree, branch, 1);271 }272 273 // 'tail-recursive' helper274 private int GetBranchLevelHelper(IFunctionTree tree, IFunctionTree branch, int level) {275 if(branch == tree) return level;276 277 foreach(IFunctionTree subTree in tree.SubTrees) {278 int result = GetBranchLevelHelper(subTree, branch, level + 1);279 if(result != -1) return result;280 }281 282 return -1;283 }284 285 internal bool IsValidTree(IFunctionTree tree) {286 foreach(IConstraint constraint in tree.Function.Constraints) {287 if(constraint is NumberOfSubOperatorsConstraint) {288 int max = ((NumberOfSubOperatorsConstraint)constraint).MaxOperators.Data;289 int min = ((NumberOfSubOperatorsConstraint)constraint).MinOperators.Data;290 if(tree.SubTrees.Count < min || tree.SubTrees.Count > max)291 return false;292 }293 }294 foreach(IFunctionTree subTree in tree.SubTrees) {295 if(!IsValidTree(subTree)) return false;296 }297 return true;298 }299 300 // returns a random branch from the specified level in the tree301 internal IFunctionTree GetRandomBranch(IFunctionTree tree, int level) {302 if(level == 0) return tree;303 List<IFunctionTree> branches = GetBranchesAtLevel(tree, level);304 return branches[random.Next(branches.Count)];305 }306 #endregion307 308 #region function information (arity, allowed childs and parents)309 internal ICollection<IFunction> GetPossibleParents(List<IFunction> list) {310 List<IFunction> result = new List<IFunction>();311 foreach(IFunction f in functions) {312 if(IsPossibleParent(f, list)) {313 result.Add(f);314 }315 }316 return result;317 }318 319 private bool IsPossibleParent(IFunction f, List<IFunction> children) {320 int minArity;321 int maxArity;322 GetMinMaxArity(f, out minArity, out maxArity);323 324 // note: we can't assume that the operators in the children list have different types!325 326 // when the maxArity of this function is smaller than the list of operators that327 // should be included as sub-operators then it can't be a parent328 if(maxArity < children.Count()) {329 return false;330 }331 int nSlots = Math.Max(minArity, children.Count);332 333 SubOperatorsConstraintAnalyser analyzer = new SubOperatorsConstraintAnalyser();334 analyzer.AllPossibleOperators = children.Cast<IOperator>().ToArray<IOperator>();335 336 List<HashSet<IFunction>> slotSets = new List<HashSet<IFunction>>();337 338 // we iterate through all slots for sub-trees and calculate the set of339 // allowed functions for this slot.340 // we only count those slots that can hold at least one of the children that we should combine341 for(int slot = 0; slot < nSlots; slot++) {342 HashSet<IFunction> functionSet = new HashSet<IFunction>(analyzer.GetAllowedOperators(f, slot).Cast<IFunction>());343 if(functionSet.Count() > 0) {344 slotSets.Add(functionSet);345 }346 }347 348 // ok at the end of this operation we know how many slots of the parent can actually349 // hold one of our children.350 // if the number of slots is smaller than the number of children we can be sure that351 // we can never combine all children as sub-trees of the function and thus the function352 // can't be a parent.353 if(slotSets.Count() < children.Count()) {354 return false;355 }356 357 // finally we sort the sets by size and beginning from the first set select one358 // function for the slot and thus remove it as possible sub-tree from the remaining sets.359 // when we can successfully assign all available children to a slot the function is a valid parent360 // when only a subset of all children can be assigned to slots the function is no valid parent361 slotSets.Sort((p, q) => p.Count() - q.Count());362 363 int assignments = 0;364 for(int i = 0; i < slotSets.Count() - 1; i++) {365 if(slotSets[i].Count > 0) {366 IFunction selected = slotSets[i].ElementAt(0);367 assignments++;368 for(int j = i + 1; j < slotSets.Count(); j++) {369 slotSets[j].Remove(selected);370 }371 }372 }373 374 // sanity check375 if(assignments > children.Count) throw new InvalidProgramException();376 return assignments == children.Count - 1;377 }378 internal IList<IFunction> GetAllowedParents(IFunction child, int childIndex) {379 List<IFunction> parents = new List<IFunction>();380 foreach(IFunction function in functions) {381 ICollection<IFunction> allowedSubFunctions = GetAllowedSubFunctions(function, childIndex);382 if(allowedSubFunctions.Contains(child)) {383 parents.Add(function);384 }385 }386 return parents;387 }388 internal bool IsTerminal(IFunction f) {389 int minArity;390 int maxArity;391 GetMinMaxArity(f, out minArity, out maxArity);392 return minArity == 0 && maxArity == 0;393 }394 internal IList<IFunction> GetAllowedSubFunctions(IFunction f, int index) {395 if(f == null) {396 return allFunctions;397 } else {398 ItemList slotList = (ItemList)f.GetVariable(GPOperatorLibrary.ALLOWED_SUBOPERATORS).Value;399 List<IFunction> result = new List<IFunction>();400 foreach(IFunction function in (ItemList)slotList[index]) {401 result.Add(function);402 }403 return result;404 }405 }406 internal void GetMinMaxArity(IFunction f, out int minArity, out int maxArity) {407 foreach(IConstraint constraint in f.Constraints) {408 NumberOfSubOperatorsConstraint theConstraint = constraint as NumberOfSubOperatorsConstraint;409 if(theConstraint != null) {410 minArity = theConstraint.MinOperators.Data;411 maxArity = theConstraint.MaxOperators.Data;412 return;413 }414 }415 // the default arity is 2416 minArity = 2;417 maxArity = 2;418 }419 #endregion420 421 #region private utility methods422 423 439 private int GetMinimalTreeHeight(IOperator op) { 424 440 return ((IntData)op.GetVariable(GPOperatorLibrary.MIN_TREE_HEIGHT).Value).Data;
Note: See TracChangeset
for help on using the changeset viewer.