public TGPOperator FindRandomOperator(TGPOperator current_operator = null)
        {
            for (int attempts = 0; attempts < 10; attempts++)
            {
                double r = mWeightSum * DistributionModel.GetUniform();

                double current_sum = 0;
                foreach (KeyValuePair <TGPOperator, double> point in mOperators)
                {
                    current_sum += point.Value;
                    if (current_sum >= r)
                    {
                        if (point.Key != current_operator)
                        {
                            return(point.Key);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            return(current_operator);
        }
        public TGPOperator FindRandomOperator(int parameter_count, TGPOperator current_operator = null)
        {
            TGPOperator selected_op = null;

            for (int attempts = 0; attempts < 10; attempts++)
            {
                double r = mWeightSum * DistributionModel.GetUniform();

                double current_sum = 0;
                foreach (KeyValuePair <TGPOperator, double> point in mOperators)
                {
                    if (selected_op == null && point.Key.Arity == parameter_count && point.Key != current_operator)
                    {
                        selected_op = point.Key;
                    }
                    current_sum += point.Value;
                    if (current_sum >= r)
                    {
                        if (point.Key != current_operator && point.Key.Arity == parameter_count)
                        {
                            return(point.Key);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            return(selected_op);
        }
        /// <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;
                }
            }
        }
        /// <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 is used by the "RandomBranch" initialization algorithm to obtain a random function node with arity less than s
        /// </summary>
        /// <param name="s">The tree size</param>
        /// <returns></returns>
        private TGPOperator FindRandomOperatorWithArityLessThan(int s)
        {
            List <TGPOperator> ops = new List <TGPOperator>();

            for (int i = 0; i < mOperatorSet.OperatorCount; ++i)
            {
                TGPOperator op1 = mOperatorSet.FindOperatorByIndex(i);
                if (op1.Arity < s)
                {
                    ops.Add(op1);
                }
            }
            if (ops.Count == 0)
            {
                return(null);
            }
            return(ops[DistributionModel.NextInt(ops.Count)]);
        }
        /// <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 AddOperator(TGPOperator op, double weight = 1)
 {
     mOperators.Add(new KeyValuePair <TGPOperator, double>(op, weight));
     op.mOperatorIndex = mOperators.Count - 1;
     mWeightSum       += weight;
 }