/// <summary> /// Method that implements the "Point Mutation" described in Section 2.4 of "A Field Guide to Genetic Programming" /// In Section 5.2.2 of "A Field Guide to Genetic Programming", this is also described as node replacement mutation /// </summary> public virtual void MicroMutate() { TGPNode node = FindRandomNode(); if (node.IsTerminal) { TGPTerminal terminal = FindRandomTerminal(); int trials = 0; int max_trials = 50; while (node.Primitive == terminal) { terminal = FindRandomTerminal(); trials++; if (trials > max_trials) { break; } } if (terminal != null) { node.Primitive = terminal; } } else { int parameter_count = node.Arity; TGPOperator op = mOperatorSet.FindRandomOperator(parameter_count, (TGPOperator)node.Primitive); if (op != null) { node.Primitive = op; } } }
public void Swap(TGPNode point2) { TGPNode parent1 = this.mParent; TGPNode parent2 = point2.mParent; if (parent1 == null || parent2 == null) { TGPPrimitive content1 = this.mData; TGPPrimitive content2 = point2.mData; this.mData = content2; point2.mData = content1; List <TGPNode> children1 = this.mChildNodes.ToList(); List <TGPNode> children2 = point2.mChildNodes.ToList(); this.RemoveAllChildren(); point2.RemoveAllChildren(); for (int i = 0; i < children1.Count; ++i) { point2.mChildNodes.Add(children1[i]); children1[i].Parent = point2; } for (int i = 0; i < children2.Count; ++i) { this.mChildNodes.Add(children2[i]); children2[i].Parent = this; } } else { int child_index1 = parent1.IndexOfChild(this); int child_index2 = parent2.IndexOfChild(point2); parent1.ReplaceChildAt(child_index1, point2); parent2.ReplaceChildAt(child_index2, this); } }
/// <summary> /// Population Initialization method following the "PTC1" method described in "Sean Luke. Two fast tree-creation algorithms for genetic programming. IEEE Transactions in Evolutionary Computation, 4(3), 2000b." /// </summary> /// <param name="parent_node">The node for which the child nodes are generated in this method</param> /// <param name="p">expected probability</param> /// <param name="allowableDepth">The maximum tree depth</param> private void PTC1(TGPNode parent_node, double p, int allowableDepth) { int child_count = parent_node.Arity; for (int i = 0; i != child_count; i++) { TGPPrimitive data = null; if (allowableDepth == 0) { data = FindRandomTerminal(); } else if (DistributionModel.GetUniform() <= p) { data = mOperatorSet.FindRandomOperator(); } else { data = FindRandomTerminal(); } TGPNode child = parent_node.CreateChild(data); if (!data.IsTerminal) { PTC1(child, p, allowableDepth - 1); } } }
public TGPNode CreateChild(TGPPrimitive data) { TGPNode node = new TGPNode(data, this); mChildNodes.Add(node); return(node); }
/// <summary> /// Method that creates a GP tree with a maximum tree depth /// </summary> /// <param name="allowableDepth">The maximum tree depth</param> /// <param name="method">The name of the method used to create the GP tree</param> /// <param name="tag">The additional information used to create the GP tree if any</param> public void CreateWithDepth(int allowableDepth, string method, object tag = null) { // Population Initialization method following the "RandomBranch" method described in "Kumar Chellapilla. Evolving computer programs without subtree crossover. IEEE Transactions on Evolutionary Computation, 1(3):209–216, September 1997." if (method == INITIALIZATION_METHOD_RANDOMBRANCH) { int s = allowableDepth; //tree size TGPOperator non_terminal = FindRandomOperatorWithArityLessThan(s); if (non_terminal == null) { mRootNode = new TGPNode(FindRandomTerminal()); } else { mRootNode = new TGPNode(non_terminal); int b_n = non_terminal.Arity; s = (int)System.Math.Floor((double)s / b_n); RandomBranch(mRootNode, s); } CalcLength(); CalcDepth(); } // Population Initialization method following the "PTC1" method described in "Sean Luke. Two fast tree-creation algorithms for genetic programming. IEEE Transactions in Evolutionary Computation, 4(3), 2000b." else if (method == INITIALIZATION_METHOD_PTC1) { int expectedTreeSize = Convert.ToInt32(tag); int b_n_sum = 0; for (int i = 0; i < mOperatorSet.OperatorCount; ++i) { b_n_sum += mOperatorSet.FindOperatorByIndex(i).Arity; } double p = (1 - 1.0 / expectedTreeSize) / ((double)b_n_sum / mOperatorSet.OperatorCount); TGPPrimitive data = null; if (DistributionModel.GetUniform() <= p) { data = mOperatorSet.FindRandomOperator(); } else { data = FindRandomTerminal(); } mRootNode = new TGPNode(data); PTC1(mRootNode, p, allowableDepth - 1); CalcLength(); CalcDepth(); } else // handle full and grow method { mRootNode = new TGPNode(FindRandomPrimitive(allowableDepth, method)); CreateWithDepth(mRootNode, allowableDepth - 1, method); CalcLength(); CalcDepth(); } }
/// <summary> /// Method that traverse the subtree and randomly returns a node from one of the leave or function node /// </summary> /// <param name="pRoot">The root node of a subtree</param> /// <param name="node_depth">The depth at which the selected node is returned</param> /// <returns>The randomly selected node by traversing</returns> public TGPNode FindRandomNodeByTraversing(TGPNode pRoot, ref int node_depth) { int child_count = pRoot.Arity; int current_node_depth = node_depth; if (child_count == 0) { return(pRoot); } TGPNode pSelectedGene = null; int selected_child_node_depth = node_depth; for (int iChild = 0; iChild != child_count; iChild++) { TGPNode pChild = pRoot.FindChildByIndex(iChild); int child_node_depth = node_depth + 1; TGPNode pChildPickedGene = FindRandomNodeByTraversing(pChild, ref child_node_depth); if (pChildPickedGene != null) { if (pSelectedGene == null) { selected_child_node_depth = child_node_depth; pSelectedGene = pChildPickedGene; } else { double selection_prob = pChildPickedGene.IsTerminal ? 0.1 : 0.9; if (DistributionModel.GetUniform() < selection_prob) { selected_child_node_depth = child_node_depth; pSelectedGene = pChildPickedGene; } } } } if (pSelectedGene == null) { node_depth = current_node_depth; pSelectedGene = pRoot; } else { node_depth = selected_child_node_depth; if (DistributionModel.GetUniform() < 0.5) { node_depth = current_node_depth; pSelectedGene = pRoot; } } return(pSelectedGene); }
/// <summary> /// Method that performs deep copy of another GP /// </summary> /// <param name="rhs">The GP to copy</param> public virtual void Copy(TGPProgram rhs) { mDepth = rhs.mDepth; mLength = rhs.mLength; if (rhs.mRootNode != null) { mRootNode = rhs.mRootNode.Clone(); } }
public int IndexOfChild(TGPNode child) { for (int i = 0; i < mChildNodes.Count; ++i) { if (mChildNodes[i] == child) { return(i); } } return(-1); }
/// <summary> /// Method that implements the subtree mutation or "headless chicken" crossover described in Section 2.4 of "A Field Guide to Genetic Programming" /// </summary> /// <param name="iMaxProgramDepth">The max depth of the tree after the mutation</param> public void Mutate(int iMaxProgramDepth, string method, object tag = null) { if (method == MUTATION_SUBTREE || method == MUTATION_SUBTREE_KINNEAR) { TGPNode node = FindRandomNode(); if (method == MUTATION_SUBTREE) { int node_depth = mRootNode.FindDepth2Node(node); node.RemoveAllChildren(); node.Primitive = FindRandomPrimitive(); if (!node.Primitive.IsTerminal) { int max_depth = iMaxProgramDepth - node_depth; CreateWithDepth(node, max_depth, INITIALIZATION_METHOD_GROW); } } else { int subtree_depth = mRootNode.FindDepth2Node(node); int current_depth = mDepth - subtree_depth; int max_depth = (int)(mDepth * 1.15) - current_depth; node.RemoveAllChildren(); node.Primitive = FindRandomPrimitive(); if (!node.Primitive.IsTerminal) { CreateWithDepth(node, max_depth, INITIALIZATION_METHOD_GROW); } } } else if (method == MUTATION_HOIST) { TGPNode node = FindRandomNode(); if (node != mRootNode) { node.Parent = null; mRootNode = node; } } else if (method == MUTATION_SHRINK) { TGPNode node = FindRandomNode(); node.RemoveAllChildren(); node.Primitive = FindRandomTerminal(); } CalcDepth(); CalcLength(); }
public virtual TGPNode Clone() { TGPNode clone = new TGPNode(mData, mParent); foreach (TGPNode child_node in mChildNodes) { TGPNode cloned_child = child_node.Clone(); cloned_child.mParent = clone; clone.mChildNodes.Add(cloned_child); } return(clone); }
/// <summary> /// Method that creates a subtree of maximum depth /// </summary> /// <param name="pRoot">The root node of the subtree</param> /// <param name="allowableDepth">The maximum depth</param> /// <param name="method">The method used to build the subtree</param> public void CreateWithDepth(TGPNode pRoot, int allowableDepth, string method) { int child_count = pRoot.Arity; for (int i = 0; i != child_count; ++i) { TGPPrimitive primitive = FindRandomPrimitive(allowableDepth, method); TGPNode child = pRoot.CreateChild(primitive); if (!primitive.IsTerminal) { CreateWithDepth(child, allowableDepth - 1, method); } } }
internal int FindDepth2Node(TGPNode node, int depthSoFar = 0) { if (this == node) { return(depthSoFar); } int maxDepthOfChild = -1; foreach (TGPNode child_node in mChildNodes) { int d = child_node.FindDepth2Node(node, depthSoFar + 1); if (d > maxDepthOfChild) { maxDepthOfChild = d; } } return(maxDepthOfChild); }
/// <summary> /// Population Initialization Method described in "Kumar Chellapilla. Evolving computer programs without subtree crossover. IEEE Transactions on Evolutionary Computation, 1(3):209–216, September 1997." /// </summary> /// <param name="parent_node"></param> /// <param name="s"></param> /// <param name="?"></param> private void RandomBranch(TGPNode parent_node, int s) { int child_count = parent_node.Arity; for (int i = 0; i != child_count; i++) { TGPOperator non_terminal = FindRandomOperatorWithArityLessThan(s); if (non_terminal == null) { TGPNode child = parent_node.CreateChild(FindRandomTerminal()); } else { TGPNode child = parent_node.CreateChild(non_terminal); int b_n = non_terminal.Arity; int s_pi = (int)System.Math.Floor((double)s / b_n); RandomBranch(child, s_pi); } } }
public void ReplaceChildAt(int index, TGPNode child) { mChildNodes[index] = child; child.mParent = this; }
public void RemoveChild(TGPNode child) { mChildNodes.Remove(child); child.Parent = null; }
public TGPNode(TGPPrimitive data, TGPNode parent = null) { mData = data; mParent = parent; }
/// <summary> /// Method that implements the subtree crossover described in Section 2.4 of "A Field Guide to Genetic Programming" /// </summary> /// <param name="rhs">Another tree to be crossover with</param> /// <param name="iMaxDepthForCrossover">The maximum depth of the trees after the crossover</param> public virtual void SubtreeCrossover(TGPProgram rhs, int iMaxDepthForCrossover, string method, object tag = null) { if (method == CROSSOVER_SUBTREE_BIAS || method == CROSSVOER_SUBTREE_NO_BIAS) { bool bias = (method == CROSSOVER_SUBTREE_BIAS); int iMaxDepth1 = CalcDepth(); int iMaxDepth2 = rhs.CalcDepth(); TGPNode pCutPoint1 = null; TGPNode pCutPoint2 = null; bool is_crossover_performed = false; // Suppose that at the beginning both the current GP and the other GP do not violate max depth constraint // then try to see whether a crossover can be performed in such a way that after the crossover, both GP still have depth <= max depth if (iMaxDepth1 <= iMaxDepthForCrossover && iMaxDepth2 <= iMaxDepthForCrossover) { int max_trials = 50; int trials = 0; do { pCutPoint1 = FindRandomNode(bias); pCutPoint2 = rhs.FindRandomNode(bias); if (pCutPoint1 != null && pCutPoint2 != null) { pCutPoint1.Swap(pCutPoint2); iMaxDepth1 = CalcDepth(); iMaxDepth2 = rhs.CalcDepth(); if (iMaxDepth1 <= iMaxDepthForCrossover && iMaxDepth2 <= iMaxDepthForCrossover) //crossover is successful { is_crossover_performed = true; break; } else { pCutPoint1.Swap(pCutPoint2); // swap back so as to restore to the original GP trees if the crossover is not valid due to max depth violation } } trials++; } while (trials < max_trials); } // force at least one crossover even if the maximum depth is violated above so that this operator won't end up like a reproduction operator if (!is_crossover_performed) { pCutPoint1 = FindRandomNode(bias); pCutPoint2 = rhs.FindRandomNode(bias); if (pCutPoint1 != null && pCutPoint2 != null) { pCutPoint1.Swap(pCutPoint2); CalcLength(); rhs.CalcLength(); } } } }