/** * Recursively travel the tree so that depth and subtree below are computed * only once and can be reused later. * * @param node * @param nodeToDepth */ public void TraverseTreeForDepth(GPNode node, ArrayList nodeToDepth, Hashtable sizeToNodes) { GPNode[] children = node.Children; NodeInfo nodeInfo = new NodeInfo(node, node.NumNodes(GP.GPNode.NODESEARCH_NONTERMINALS)); nodeToDepth.Add(nodeInfo); // check to see if there is list in map for that size LinkedList <NodeInfo> listForSize = (LinkedList <NodeInfo>)sizeToNodes[nodeInfo.NumberOfSubTreesBeneath]; if (listForSize == null) { listForSize = new LinkedList <NodeInfo>(); sizeToNodes[nodeInfo.NumberOfSubTreesBeneath] = listForSize; } // add it to the list no matter what listForSize.AddLast(nodeInfo); // recurse if (children.Length > 0) { foreach (GPNode t in children) { TraverseTreeForDepth(t, nodeToDepth, sizeToNodes); } } }
/// <summary> /// Returns true if inner1 can feasibly be swapped into inner2's position /// </summary> private bool VerifyPoints(GPNode inner1, GPNode inner2) { // We know they're swap-compatible since we generated inner1 // to be exactly that. So don't bother. // next check to see if inner1 can fit in inner2's spot if (inner1.Depth + inner2.AtDepth() > MaxDepth) { return(false); } // check for size if (MaxSize != NO_SIZE_LIMIT) { // first easy check var inner1Size = inner1.NumNodes(GPNode.NODESEARCH_ALL); var inner2Size = inner2.NumNodes(GPNode.NODESEARCH_ALL); if (inner1Size > inner2Size) // need to test further { // let's keep on going for the more complex test GPNode root2 = ((GPTree)(inner2.RootParent())).Child; var root2Size = root2.NumNodes(GPNode.NODESEARCH_ALL); if (root2Size - inner2Size + inner1Size > MaxSize) // take root2, remove inner2 and swap in inner1. Is it still small enough? { return(false); } } } // checks done! return(true); }
private static int NumDemotableNodes(GPInitializer initializer, GPNode root, int soFar, GPFunctionSet funcs) { // if I have just one type, skip this and just return // the number of nonterminals in the tree if (initializer.NumAtomicTypes + initializer.NumSetTypes == 1) { return(root.NumNodes(GPNode.NODESEARCH_ALL)); } // otherwise, I gotta do the dirty work return(NumDemotableNodesDirtyWork(initializer, root, soFar, funcs)); }
/// <summary> /// Returns true if inner1 can feasibly be swapped into inner2's position. /// </summary> public bool VerifyPoints(GPInitializer initializer, GPNode inner1, GPNode inner2) { // first check to see if inner1 is swap-compatible with inner2 // on a type basis if (!inner1.SwapCompatibleWith(initializer, inner2)) { return(false); } // next check to see if inner1 can fit in inner2's spot if (inner1.Depth + inner2.AtDepth() > MaxDepth) { return(false); } // check for size // NOTE: this is done twice, which is more costly than it should be. But // on the other hand it allows us to toss a child without testing both times // and it's simpler to have it all here in the verifyPoints code. if (MaxSize != NO_SIZE_LIMIT) { // first easy check var inner1Size = inner1.NumNodes(GPNode.NODESEARCH_ALL); var inner2Size = inner2.NumNodes(GPNode.NODESEARCH_ALL); if (inner1Size > inner2Size) // need to test further { // let's keep on going for the more complex test var root2 = ((GPTree)(inner2.RootParent())).Child; var root2Size = root2.NumNodes(GPNode.NODESEARCH_ALL); if (root2Size - inner2Size + inner1Size > MaxSize) // take root2, remove inner2 and swap in inner1. Is it still small enough? { return(false); } } } // checks done! return(true); }
/** * This method finds a node using the logic given in the langdon paper. * @param nodeToSubtrees For Tree of Parent2 all precomputed stats about depth,subtrees etc * @param sizeToNodes Quick lookup for LinkedList of size to Nodes * @param parent1SelectedNode Node selected in parent1 * @param Tree2 Tree of parent2 * @param state Evolution State passed for getting access to Random Object of MersenneTwiser * @param thread thread number */ protected GPNode FindFairSizeNode(ArrayList nodeToSubtrees, Hashtable sizeToNodes, GPNode parent1SelectedNode, GPTree tree2, IEvolutionState state, int thread) { GPNode selectedNode = null; // get the size of subtrees of parent1 int parent1SubTrees = parent1SelectedNode.NumNodes(GPNode.NODESEARCH_NONTERMINALS); // the maximum length in mate we are looking for int maxmatesublen = parent1SubTrees == 0 ? 0 : 2 * parent1SubTrees + 1; // lets see if for all lengths we have trees corresponding bool[] mateSizeAvailable = new bool[maxmatesublen + 1]; // initialize the array to false for (int i = 0; i < maxmatesublen; i++) { mateSizeAvailable[i] = false; } // check for ones we have for (int i = 0; i < nodeToSubtrees.Count; i++) { NodeInfo nodeInfo = (NodeInfo)nodeToSubtrees[i]; // get the length of trees int subtree = nodeInfo.NumberOfSubTreesBeneath; if (subtree <= maxmatesublen) { mateSizeAvailable[subtree] = true; } } // choose matesublen so mean size change=0 if possible int countOfPositives = 0; int countOfNegatives = 0; int sumOfPositives = 0; int sumOfNegatives = 0; int l; for (l = 1; l < parent1SubTrees; l++) { if (mateSizeAvailable[l]) { countOfNegatives++; sumOfNegatives += parent1SubTrees - l; } } for (l = parent1SubTrees + 1; l <= maxmatesublen; l++) { if (mateSizeAvailable[l]) { countOfPositives++; sumOfPositives += l - parent1SubTrees; } } // if they are missing use the same int mateSublengthSelected = 0; if (sumOfPositives == 0 || sumOfNegatives == 0) { //if so then check if mate has the length and use that if (mateSizeAvailable[parent1SubTrees]) { mateSublengthSelected = parent1SubTrees; } //else we go with zero } else { // probability of same is dependent on do we find same sub trees // else 0.0 double pzero = (mateSizeAvailable[parent1SubTrees]) ? 1.0 / parent1SubTrees : 0.0; // positive probability double ppositive = (1.0 - pzero) / (countOfPositives + ((double)(countOfNegatives * sumOfPositives) / (sumOfNegatives))); // negative probability double pnegative = (1.0 - pzero) / (countOfNegatives + ((double)(countOfPositives * sumOfNegatives) / (sumOfPositives))); // total probability, just for making sure math is right ;-) double total = countOfNegatives * pnegative + pzero + countOfPositives * ppositive; // putting an assert for floating point calculations, similar to what langdon does // assert(total<1.01&&total>.99); // now create a Roulette Wheel RouletteWheelSelector wheel = new RouletteWheelSelector(maxmatesublen); // add probabilities to the wheel // all below the length of parent node get pnegative // all above get ppositive and one on node gets pzero for (l = 1; l < parent1SubTrees; l++) { if (mateSizeAvailable[l]) { wheel.Add(pnegative, l); } } if (mateSizeAvailable[parent1SubTrees]) { wheel.Add(pzero, parent1SubTrees); } for (l = parent1SubTrees + 1; l <= maxmatesublen; l++) { if (mateSizeAvailable[l]) { wheel.Add(ppositive, l); } } // spin the wheel mateSublengthSelected = wheel.Roulette(state, thread); } // now we have length chosen, but there can be many nodes with that // LinkedList <NodeInfo> listOfNodes = (LinkedList <NodeInfo>)sizeToNodes[mateSublengthSelected]; if (listOfNodes == null) { state.Output.Fatal("In SizeFairCrossoverPipeline, nodes for tree length " + mateSublengthSelected + " is null, indicates some serious error"); } // in size fair we choose the elements at random for given length int chosenNode = 0; // if using fair size get random from the list if (!Homologous) { chosenNode = state.Random[thread].NextInt(listOfNodes.Count); } // if Homologous else { if (listOfNodes.Count > 1) { GPInitializer initializer = ((GPInitializer)state.Initializer); int currentMinDistance = int.MaxValue; for (int i = 0; i < listOfNodes.Count; i++) { // get the GP node GPNode selectedMateNode = listOfNodes.ElementAt(i).Node; // now lets traverse selected and parent 1 to see divergence GPNode currentMateNode = selectedMateNode; GPNode currentParent1Node = parent1SelectedNode; // found a match? bool foundAMatchInAncestor = false; int distance = 0; while (currentMateNode.Parent != null && currentMateNode.Parent is GPNode && currentParent1Node.Parent != null && currentParent1Node.Parent is GPNode && !foundAMatchInAncestor) { GPNode parent1 = (GPNode)currentParent1Node.Parent; GPNode parent2 = (GPNode)currentMateNode.Parent; // if there is match between compatibility of Parents break if (parent1.SwapCompatibleWith(initializer, parent2)) { foundAMatchInAncestor = true; break; } else { // need to go one level above of both currentMateNode = parent2; currentParent1Node = parent1; //increment the distance distance = distance + 1; } } // find the one with least distance if (distance < currentMinDistance) { currentMinDistance = distance; chosenNode = i; } } } // else take the first node, no choice } NodeInfo nodeInfoSelected = listOfNodes.ElementAt(chosenNode); selectedNode = nodeInfoSelected.Node; return(selectedNode); }
public override int Produce( int min, int max, int subpop, IList <Individual> inds, IEvolutionState state, int thread, IDictionary <string, object> misc) { int start = inds.Count; // grab individuals from our source and stick 'em right into inds. // we'll modify them from there var n = Sources[0].Produce(min, max, subpop, inds, state, thread, misc); // should we bother? if (!state.Random[thread].NextBoolean(Likelihood)) { return(n); } var initializer = ((GPInitializer)state.Initializer); // now let's mutate 'em for (var q = start; q < n + start; q++) { var i = (GPIndividual)inds[q]; if (Tree != TREE_UNFIXED && (Tree < 0 || Tree >= i.Trees.Length)) { // uh oh state.Output.Fatal("GP Mutation Pipeline attempted to fix Tree.0 to a value which was out of bounds" + " of the array of the individual's Trees. Check the pipeline's fixed Tree values" + " -- they may be negative or greater than the number of Trees in an individual"); } int t; // pick random Tree if (Tree == TREE_UNFIXED) { if (i.Trees.Length > 1) { t = state.Random[thread].NextInt(i.Trees.Length); } else { t = 0; } } else { t = Tree; } // validity result... var res = false; // prepare the NodeSelector NodeSelect.Reset(); // pick a node GPNode p1 = null; // the node we pick GPNode p2 = null; for (var x = 0; x < NumTries; x++) { // pick a node in individual 1 p1 = NodeSelect.PickNode(state, subpop, thread, i, i.Trees[t]); // generate a Tree swap-compatible with p1's position var size = GPNodeBuilder.NOSIZEGIVEN; if (EqualSize) { size = p1.NumNodes(GPNode.NODESEARCH_ALL); } p2 = Builder.NewRootedTree(state, p1.ParentType(initializer), thread, p1.Parent, i.Trees[t].Constraints(initializer).FunctionSet, p1.ArgPosition, size); // check for depth and swap-compatibility limits res = VerifyPoints(p2, p1); // p2 can fit in p1's spot -- the order is important! // did we get something that had both nodes verified? if (res) { break; } } if (res) // we're in business { p2.Parent = p1.Parent; p2.ArgPosition = p1.ArgPosition; if (p2.Parent is GPNode) { ((GPNode)p2.Parent).Children[p2.ArgPosition] = p2; } else { ((GPTree)p2.Parent).Child = p2; } i.Evaluated = false; // we've modified it } // add the new individual, replacing its previous source inds[q] = i; } return(n); }