/// <summary> /// Internal method to get the mutation done. This method returns a reference /// to the root node of the branch. If the first node is selected for mutation, /// that node will change, therefore, it needs to be updated in the calling method. /// </summary> /// <param name="BranchRoot">Root node of the recursion branch we are mutating</param> /// <param name="CountNodes">Number of nodes in the branch</param> /// <param name="DepthInitial">Initial depth the branch was created with</param> private void Mutate(ref GPNode BranchRoot, int NodeCount, int DepthInitial) { // // Step 1: Select a node randomly int NodeLabel = GPUtilities.rngNextInt(NodeCount); // // Step 2: Find this node, its parent and which child of the parent it is GPProgramBranchFactory.FindResult find = FindNode(null, BranchRoot, NodeLabel); // // Step 3: Build a new subtree that will replace the selected node GPNode SubTreeNew = BuildInternal(GPEnums.TreeBuild.Grow, DepthInitial, BranchRoot == m_BranchADR.m_RBB); // // If the parent of the result is null, then we are replacing the root node, // otherwise we are replacing a child of the parent. if (find.Parent == null) { BranchRoot = SubTreeNew; } else { find.Parent.Children[find.ChildNumber] = SubTreeNew; } }
/// <summary> /// Handles mutation of the RPB branch. A node is randomly selected /// for mutation and a new branch is built from that location. /// </summary> public override void Mutate() { // // Step 1: Select a node randomly int NodeLabel = GPUtilities.rngNextInt(m_Branch.CountNodes); // // Step 2: Find this node, its parent and which child of the parent it is GPProgramBranchFactory.FindResult find = FindNode(null, m_Branch.Root, NodeLabel); // // Step 3: Build a new subtree that will replace the selected node // Assign a current depth of 2, to allow a terminal to mutate into the location GPNode newSubtree = null; if (find.Node is GPNodeFunction) { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, m_Branch.DepthInitial, 2, ((GPNodeFunction)find.Node).TerminalParameters); } else { // // Now, even if this node is a terminal, it's parent might be a function that can only accept // terminal parameters. If that is the case, can only mutate by create a new terminal node if (find.Parent is GPNodeFunction) { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, m_Branch.DepthInitial, 2, ((GPNodeFunction)find.Parent).TerminalParameters); } else { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, m_Branch.DepthInitial, 2, false); } } // // If the parent of the result is null, then we are replacing the root node, // otherwise we are replacing a child of the parent. if (find.Parent == null) { m_Branch.Root = newSubtree; } else { find.Parent.Children[find.ChildNumber] = newSubtree; } // // Update the stats for this tree m_Branch.UpdateStats(); }
/// <summary> /// Internal method to get the mutation done. This method returns a reference /// to the root node of the branch. If the first node is selected for mutation, /// that node will change, therefore, it needs to be updated in the calling method. /// </summary> /// <param name="BranchRoot">Root node of the loop branch we are mutating</param> /// <param name="CountNodes">Number of nodes in the branch</param> /// <param name="DepthInitial">Initial depth the branch was created with</param> private void Mutate(ref GPNode BranchRoot, int NodeCount, int DepthInitial) { // // Step 1: Select a node randomly int NodeLabel = GPUtilities.rngNextInt(NodeCount); // // Step 2: Find this node, its parent and which child of the parent it is GPProgramBranchFactory.FindResult find = FindNode(null, BranchRoot, NodeLabel); // // Step 3: Build a new subtree that will replace the selected node GPNode newSubtree = null; if (find.Node is GPNodeFunction) { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, DepthInitial, ((GPNodeFunction)find.Node).TerminalParameters); } else { // // Now, even if this node is a terminal, it's parent might be a function that can only accept // terminal parameters. If that is the case, can only mutate by creating a new terminal node if (find.Parent is GPNodeFunction) { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, DepthInitial, ((GPNodeFunction)find.Parent).TerminalParameters); } else { newSubtree = BuildInternal(GPEnums.TreeBuild.Grow, DepthInitial, false); } } // // If the parent of the result is null, then we are replacing the root node, // otherwise we are replacing a child of the parent. if (find.Parent == null) { BranchRoot = newSubtree; } else { find.Parent.Children[find.ChildNumber] = newSubtree; } }
/// <summary> /// This method performs crossover on the result producing branch. /// 90% of the time internal nodes are selected and 10% of the time /// leaf nodes are selected. /// TODO: Parameterize those percentages /// /// If either one of the selected nodes is a function that accepts only /// terminals as parameters, no crossover is performed. /// /// </summary> /// <param name="sibling"></param> public override void Crossover(GPProgramBranch sibling) { GPProgramBranchRPB rightRPB = (GPProgramBranchRPB)sibling; // // Step 1: Find a node in the left tree double TypeLeft = GPUtilities.rngNextDouble(); GPProgramBranchFactory.FindResult findLeft = null; bool DoneLeft = false; while (!DoneLeft) { int NodeLeft = GPUtilities.rngNextInt(m_Branch.CountNodes); findLeft = FindNode(null, m_Branch.Root, NodeLeft); if (TypeLeft < 0.90 && (findLeft.Node is GPNodeFunction)) { DoneLeft = true; } else if (TypeLeft >= 0.90 && (findLeft.Node is GPNodeTerminal)) { DoneLeft = true; } else if (TypeLeft >= 0.90 && (findLeft.Node is GPNodeFunction) && ((GPNodeFunction)findLeft.Node).Children.Count == 0) { // // This if statement accounts for the possibility of functions that // are constant values...because I didn't use a terminal type for them DoneLeft = true; } else if (m_Branch.CountNodes == 1) { DoneLeft = true; } } // // If the node is a function that only accepts terminal inputs, then crossover is not allowed if (findLeft.Node is GPNodeFunction && ((GPNodeFunction)findLeft.Node).TerminalParameters) { return; } if (findLeft.Parent != null && findLeft.Parent is GPNodeFunction && ((GPNodeFunction)findLeft.Parent).TerminalParameters) { return; } // // Step 2: Find a node in the right tree double TypeRight = GPUtilities.rngNextDouble(); GPProgramBranchFactory.FindResult findRight = null; bool DoneRight = false; while (!DoneRight) { int NodeRight = GPUtilities.rngNextInt(rightRPB.CountNodes); findRight = FindNode(null, rightRPB.Root, NodeRight); if (TypeRight < 0.90 && (findRight.Node is GPNodeFunction)) { DoneRight = true; } else if (TypeRight >= 0.90 && (findRight.Node is GPNodeTerminal)) { DoneRight = true; } else if (TypeRight >= 0.90 && (findRight.Node is GPNodeFunction) && ((GPNodeFunction)findRight.Node).Children.Count == 0) { // // This if statement accounts for the possibility of functions that // are constant values...because I didn't use a terminal type for them DoneRight = true; } else if (rightRPB.CountNodes == 1) { DoneRight = true; } } // // If the node is a function that only accepts terminal inputs, then crossover is not allowed if (findRight.Node is GPNodeFunction && ((GPNodeFunction)findRight.Node).TerminalParameters) { return; } if (findRight.Parent != null && findRight.Parent is GPNodeFunction && ((GPNodeFunction)findRight.Parent).TerminalParameters) { return; } // // Step 3: Swap the references if (findLeft.Parent == null) { m_Branch.Root = findRight.Node; } else { findLeft.Parent.Children[findLeft.ChildNumber] = findRight.Node; } if (findRight.Parent == null) { rightRPB.Root = findLeft.Node; } else { findRight.Parent.Children[findRight.ChildNumber] = findLeft.Node; } // // Update the stats for these trees m_Branch.UpdateStats(); rightRPB.UpdateStats(); }
/// <summary> /// Internal method that actually does the crossover operation. 90% of the /// time a functional node is selected, 10% of the time a terminal is selected. /// TODO: Think about parameterizing those percentages /// </summary> /// <param name="LeftBranchRoot">Root node of the left sibling</param> /// <param name="LeftNodeCount">Number of nodes in the left sibling</param> /// <param name="RightBranchRoot">Root node of the right sibling</param> /// <param name="RightNodeCount">Number of nodes in the right sibling</param> private void Crossover(ref GPNode LeftBranchRoot, int LeftNodeCount, ref GPNode RightBranchRoot, int RightNodeCount) { // // Step 1: Find a node in the left tree double TypeLeft = GPUtilities.rngNextDouble(); GPProgramBranchFactory.FindResult findLeft = null; bool DoneLeft = false; while (!DoneLeft) { int NodeLeft = GPUtilities.rngNextInt(LeftNodeCount); findLeft = FindNode(null, LeftBranchRoot, NodeLeft); if (TypeLeft < 0.90 && (findLeft.Node is GPNodeFunction)) { DoneLeft = true; } else if (TypeLeft >= 0.90 && (findLeft.Node is GPNodeTerminal)) { DoneLeft = true; } else if (LeftNodeCount == 1) { DoneLeft = true; } } // // Step 2: Find a node in the right tree double TypeRight = GPUtilities.rngNextDouble(); GPProgramBranchFactory.FindResult findRight = null; bool DoneRight = false; while (!DoneRight) { int NodeRight = GPUtilities.rngNextInt(RightNodeCount); findRight = FindNode(null, RightBranchRoot, NodeRight); if (TypeRight < 0.90 && (findRight.Node is GPNodeFunction)) { DoneRight = true; } else if (TypeRight >= 0.90 && (findRight.Node is GPNodeTerminal)) { DoneRight = true; } else if (RightNodeCount == 1) { DoneRight = true; } } // // Step 3: Swap the references if (findLeft.Parent == null) { LeftBranchRoot = findRight.Node; } else { findLeft.Parent.Children[findLeft.ChildNumber] = findRight.Node; } if (findRight.Parent == null) { RightBranchRoot = findLeft.Node; } else { findRight.Parent.Children[findRight.ChildNumber] = findLeft.Node; } }