/// <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 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);
            }
        }