/// <summary> /// Recursive helper method for placing given subtree at the specific point (at node with index). /// </summary> /// /// <param name="node">Chromosome (or its child node) to be changed.</param> /// <param name="indexOfCrossoverPointOfPrimaryParent">Index of changing point.</param> /// <param name="crossoverSubtreeOfSecundaryParent">Subtree to be added at changing point.</param> /// <param name="found">Reference to a variable that represents if node with given index is found. It is used for better preformance.</param> /// /// <returns> New, or old, (sub)tree. </returns> public Tuple <SymbolicTreeNode, bool> PlaceNodeAtPoint(SymbolicTreeNode node, int indexOfCrossoverPointOfPrimaryParent, SymbolicTreeNode crossoverSubtreeOfSecundaryParent, ref bool found) { // Node is previously found - return tuple of current node and found variable. if (found) { return(new Tuple <SymbolicTreeNode, bool>(node, found)); } // If node is null call to the method should not be preformed. if (node == null) { throw new Exception("[PlaceNodeAtPoint] Node is null. Not possible since all cases should be already covered."); } if (node.arity == 0) { // If terminal node. #region exceptions // Check that node type is terminal. if (node.type != "terminal") { throw new Exception("[PlaceNodeAtPoint] Node has arity = 0 but his type is: " + node.type + " (not terminal)."); } // Check that this node has no child node. if (!(node.children == null || node.children.Count == 0)) { throw new Exception("[PlaceNodeAtPoint] Node has arity = 0 but has " + node.children.Count + " child nodes."); } #endregion #region check if current node is the one (return if true) // Everything fine, check if we found right node. if (indexOfCrossoverPointOfPrimaryParent == node.index) { // Save current depth. int currentDepth = node.depth; // Update node. node = (SymbolicTreeNode)crossoverSubtreeOfSecundaryParent.Clone(); // Update variable found. found = true; // Update depths of new subtree. node.CalculateDepths(currentDepth); return(new Tuple <SymbolicTreeNode, bool>(node, found)); } #endregion // Node was not found. return(new Tuple <SymbolicTreeNode, bool>(node, found)); } else if (node.arity == 1) { // If non-terminal node with arity 1. #region exceptions // Check that node type is non-teminal. if (node.type != "non-terminal") { throw new Exception("[PlaceNodeAtPoint] Node has arity = 1 but his type is: " + node.type + " (not non-terminal)."); } // Check that this node has 1 child node. if (node.children.Count != 1) { throw new Exception("[PlaceNodeAtPoint] Node has arity = 1 but has " + node.children.Count + " child nodes."); } #endregion #region check if current node is the one (return if true) // Everything fine, check if we found right node. if (indexOfCrossoverPointOfPrimaryParent == node.index) { // Save current depth. int currentDepth = node.depth; // Update node. node = (SymbolicTreeNode)crossoverSubtreeOfSecundaryParent.Clone(); // Update variable found. found = true; // Update depths of new subtree. node.CalculateDepths(currentDepth); return(new Tuple <SymbolicTreeNode, bool>(node, found)); } #endregion #region check child (return if found) // Check subtree of current node since node is not yet found. var retVal = PlaceNodeAtPoint((SymbolicTreeNode)node.children[0].Clone(), indexOfCrossoverPointOfPrimaryParent, crossoverSubtreeOfSecundaryParent, ref found); // Update variable found. found = retVal.Item2; // Check if node is now found. if (found) { // Update node. node.children[0] = (SymbolicTreeNode)retVal.Item1.Clone(); } #endregion // Node was not found. return(new Tuple <SymbolicTreeNode, bool>(node, found)); } else if (node.arity == 2) { // If non-terminal node with arity 2. #region exceptions // Check that node type is non-teminal. if (node.type != "non-terminal") { throw new Exception("[PlaceNodeAtPoint] Node has arity = 2 but his type is: " + node.type + " (not non-terminal)."); } // Check that this node has 2 child nodes. if (node.children.Count != 2) { throw new Exception("[PlaceNodeAtPoint] Node has arity = 2 but has " + node.children.Count + " child nodes."); } #endregion #region check if current node is the one (return if true) // Everything fine, check if we found right node. if (indexOfCrossoverPointOfPrimaryParent == node.index) { // Save current depth. int currentDepth = node.depth; // Update node. node = (SymbolicTreeNode)crossoverSubtreeOfSecundaryParent.Clone(); // Update variable found. found = true; // Update depths of new subtree. node.CalculateDepths(currentDepth); return(new Tuple <SymbolicTreeNode, bool>(node, found)); } #endregion #region check left child (return if found) // Check left subtree of current node. Tuple <SymbolicTreeNode, bool> retValLeft = PlaceNodeAtPoint((SymbolicTreeNode)node.children[0].Clone(), indexOfCrossoverPointOfPrimaryParent, crossoverSubtreeOfSecundaryParent, ref found); // Update variable found. found = retValLeft.Item2; // If node now found. if (found) { // Update node left child. Right child stays the same. node.children[0] = (SymbolicTreeNode)retValLeft.Item1.Clone(); return(new Tuple <SymbolicTreeNode, bool>(node, found)); } #endregion #region check right child (return if found) // Node still not found. // Check right subtree of current node. Tuple <SymbolicTreeNode, bool> retValRight = PlaceNodeAtPoint((SymbolicTreeNode)node.children[1].Clone(), indexOfCrossoverPointOfPrimaryParent, crossoverSubtreeOfSecundaryParent, ref found); // Update variable found. found = retValRight.Item2; // If node now found. if (found) { // Update node left child. Right child stays the same. node.children[1] = (SymbolicTreeNode)retValRight.Item1.Clone(); } #endregion // Node was not found. return(new Tuple <SymbolicTreeNode, bool>(node, found)); } else { // Node with given arity is not expected. throw new Exception("[PlaceNodeAtPoint] Given node arity = " + node.arity + " is not expected! Arity higher than 2 is not covered yet!"); } }
/// <summary> /// Mehod for choosing points of crossover in parents. /// In other words, choosing subtrees of parents for crossover. /// </summary> /// /// <param name="primaryParent">Primary parent.</param> /// <param name="secundaryParent">Secundary parent.</param> /// <param name="chooseNonTerminalPointProbability">Probability for choosing non-terminal as point of crossover.</param> /// <param name="maxDepth">Maximal depth of trees in population.</param> /// <returns>Tuple of node index of primaryParent and node of secundaryParent that will be points for crossover. </returns> public Tuple <int, SymbolicTreeNode> ChooseSubtrees(Chromosome primaryParent, Chromosome secundaryParent, double chooseNonTerminalPointProbability, int maxDepth) { // Index of crossover point in primary parent. int indexOfCrossoverPointOfPrimaryParent; // Subtree of crossover point in secundary parent. SymbolicTreeNode crossoverSubtreeOfSecundaryParent = new SymbolicTreeNode(); // Search for crossover points in parents until they that satisfy condition on depth of child. while (true) { #region primary parent crossover point selection // Make list of nonTerminal and terminal indices in primaryParent. List <int> nonTerminalIndicesOfPrimaryParent = new List <int>(); List <int> terminalIndicesOfPrimaryParent = new List <int>(); SeparateIndices(primaryParent.symbolicTree, ref nonTerminalIndicesOfPrimaryParent, ref terminalIndicesOfPrimaryParent); // Randomly select non-terminal or terminal (probability of selecting non-terminal is predefined) from secundary parent. if ((rand.Next(100) < (chooseNonTerminalPointProbability * 100)) && (nonTerminalIndicesOfPrimaryParent.Count > 1)) { // Index of the (to-be) selected non-terminal. int crossoverPointOfPrimaryParent; // Do not consider crossover point at root node (index = 0) in first parent since in that way we would be cloning second parent into a child. while (true) { // Chose index of a non-terminal node from secundary parent. crossoverPointOfPrimaryParent = rand.Next(nonTerminalIndicesOfPrimaryParent.Count); if (crossoverPointOfPrimaryParent != 0) { break; } } // Clone selected subtree. indexOfCrossoverPointOfPrimaryParent = nonTerminalIndicesOfPrimaryParent[crossoverPointOfPrimaryParent]; } else { // Chose index of a non-terminal node from secundary parent. int crossoverPointOfPrimaryParent = rand.Next(terminalIndicesOfPrimaryParent.Count); // Clone selected subtree. indexOfCrossoverPointOfPrimaryParent = terminalIndicesOfPrimaryParent[crossoverPointOfPrimaryParent]; } #endregion #region secundary parent crossover point selection // Make list of nonTerminal and terminal nodes in secundaryParent. List <SymbolicTreeNode> nonTerminalNodesOfSecundaryParent = new List <SymbolicTreeNode>(); List <SymbolicTreeNode> terminalNodesOfSecundaryParent = new List <SymbolicTreeNode>(); SeparateNodes(secundaryParent.symbolicTree, ref nonTerminalNodesOfSecundaryParent, ref terminalNodesOfSecundaryParent); // Randomly select non-terminal or terminal (probability of selecting non-terminal is predefined) from secundary parent. if ((rand.Next(100) < (chooseNonTerminalPointProbability * 100)) && (nonTerminalNodesOfSecundaryParent.Count != 0)) { // Chose index of a non-terminal node from secundary parent. int crossoverPointOfSecundaryParent = rand.Next(nonTerminalNodesOfSecundaryParent.Count); // Clone selected subtree. crossoverSubtreeOfSecundaryParent = (SymbolicTreeNode)nonTerminalNodesOfSecundaryParent[crossoverPointOfSecundaryParent].Clone(); } else { // Chose index of a non-terminal node from secundary parent. int crossoverPointOfSecundaryParent = rand.Next(terminalNodesOfSecundaryParent.Count); // Clone selected subtree. crossoverSubtreeOfSecundaryParent = (SymbolicTreeNode)terminalNodesOfSecundaryParent[crossoverPointOfSecundaryParent].Clone(); } #endregion int depth1 = primaryParent.symbolicTree.FindNodeWithIndex(indexOfCrossoverPointOfPrimaryParent).depth; int depth2 = crossoverSubtreeOfSecundaryParent.DepthOfSymbolicTree(); if (depth1 + depth2 < maxDepth) { break; } } return(Tuple.Create(indexOfCrossoverPointOfPrimaryParent, crossoverSubtreeOfSecundaryParent)); }
/// <summary> /// Recursive helper method for creating preorder list of non-terminal and terminal nodes. /// </summary> /// /// <param name="node">Root or current node.</param> /// <param name="nonTerminalNodesOfSecundaryParent">Reference of a list of non-terminal nodes.</param> /// <param name="terminalNodesOfSecundaryParent">Reference of a list of terminal nodes.</param> private void SeparateNodes(SymbolicTreeNode node, ref List <SymbolicTreeNode> nonTerminalNodesOfSecundaryParent, ref List <SymbolicTreeNode> terminalNodesOfSecundaryParent) { if (node == null) { return; } if (node.arity == 0) { // If terminal node. #region exceptions // Check that node type is terminal. if (node.type != "terminal") { throw new Exception("[SeparateNodes] Node has arity = 0 but his type is: " + node.type + " (not terminal)."); } // Check that this node has no child node. if (!(node.children == null || node.children.Count == 0)) { throw new Exception("[SeparateNodes] Node has arity = 0 but has " + node.children.Count + " child nodes."); } #endregion // Everything fine, add node to list of terminal nodes. terminalNodesOfSecundaryParent.Add(node); return; } else if (node.arity == 1) { // If non-terminal node with arity 1. #region exceptions // Check that node type is non-teminal. if (node.type != "non-terminal") { throw new Exception("[SeparateNodes] Node has arity = 1 but his type is: " + node.type + " (not non-terminal)."); } // Check that this node has 1 child node. if (node.children.Count != 1) { throw new Exception("[SeparateNodes] Node has arity = 1 but has " + node.children.Count + " child nodes."); } #endregion // Everything fine, add node to nonTerminal list and call SeparateNodes of his child node. nonTerminalNodesOfSecundaryParent.Add(node); SeparateNodes(node.children[0], ref nonTerminalNodesOfSecundaryParent, ref terminalNodesOfSecundaryParent); return; } else if (node.arity == 2) { // If non-terminal node with arity 2. #region exceptions // Check that node type is non-teminal. if (node.type != "non-terminal") { throw new Exception("[SeparateNodes] Node has arity = 2 but his type is: " + node.type + " (not non-terminal)."); } // Check that this node has 2 child nodes. if (node.children.Count != 2) { throw new Exception("[SeparateNodes] Node has arity = 2 but has " + node.children.Count + " child nodes."); } #endregion // Everything fine, call SeparateNodes on his left child node, add node to nonTerminal list and call SeparateNodes on his right child node. SeparateNodes(node.children[0], ref nonTerminalNodesOfSecundaryParent, ref terminalNodesOfSecundaryParent); nonTerminalNodesOfSecundaryParent.Add(node); SeparateNodes(node.children[1], ref nonTerminalNodesOfSecundaryParent, ref terminalNodesOfSecundaryParent); return; } else { // Node with given arity is not expected. throw new Exception("[SeparateNodes] Given node arity = " + node.arity + " is not expected! Arity higher than 2 is not covered yet!"); } }