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