/// <summary>
        /// Construct an innovation list, that includes the initial innovations.
        /// </summary>
        /// <param name="population">The population to base this innovation list on.</param>
        public NEATInnovationList(NEATPopulation population)
        {
            Population = population;

            FindInnovation(Population.AssignGeneId()); // bias

            // input neurons
            for (int i = 0; i < Population.InputCount; i++)
            {
                FindInnovation(Population.AssignGeneId());
            }

            // output neurons
            for (int i = 0; i < Population.OutputCount; i++)
            {
                FindInnovation(Population.AssignGeneId());
            }

            // connections
            for (var fromId = 0; fromId < Population.InputCount + 1; fromId++)
            {
                for (var toId = 0; toId < Population.OutputCount; toId++)
                {
                    FindInnovation(fromId, toId);
                }
            }
        }
        /// <summary>
        /// Construct an innovation list, that includes the initial innovations.
        /// </summary>
        /// <param name="population">The population to base this innovation list on.</param>
        public NEATInnovationList(NEATPopulation population)
        {
            Population = population;

            FindInnovation(Population.AssignGeneId()); // bias

            // input neurons
            for (int i = 0; i < Population.InputCount; i++)
            {
                FindInnovation(Population.AssignGeneId());
            }

            // output neurons
            for (int i = 0; i < Population.OutputCount; i++)
            {
                FindInnovation(Population.AssignGeneId());
            }

            // connections
            for (var fromId = 0; fromId < Population.InputCount + 1; fromId++)
            {
                for (var toId = 0; toId < Population.OutputCount; toId++)
                {
                    FindInnovation(fromId, toId);
                }
            }
        }
        /// <summary>
        /// Find an innovation for a hidden neuron that split a existing link. This
        /// is the means by which hidden neurons are introduced in NEAT.
        /// </summary>
        /// <param name="fromId">The source neuron ID in the link.</param>
        /// <param name="toId">The target neuron ID in the link.</param>
        /// <returns>The newly created innovation, or the one that matched the search.</returns>
        public NEATInnovation FindInnovationSplit(long fromId, long toId)
        {
            String key = ProduceKeyNeuronSplit(fromId, toId);

            lock (_list)
            {
                if (_list.ContainsKey(key))
                {
                    return(_list[key]);
                }
                long neuronId   = Population.AssignGeneId();
                var  innovation = new NEATInnovation
                {
                    InnovationId = Population.AssignInnovationId(),
                    NeuronId     = neuronId
                };
                _list[key] = innovation;

                // create other sides of split, if needed
                FindInnovation(fromId, neuronId);
                FindInnovation(neuronId, toId);
                return(innovation);
            }
        }