/// <summary>
        /// Initialise agent and prey positions. The prey is positioned randomly with at least 4 empty squares between it and a wall (in all directions).
        /// The agent is positioned randomly but such that the prey is within sensor range (distance 2 or less).
        /// </summary>
        public void InitPositions()
        {
            // Random position at least 4 units away from any wall.
            _preyPos.X = 4 + _rng.Next(__gridSize - 8);
            _preyPos.Y = 4 + _rng.Next(__gridSize - 8);

            // Agent position. The angle from the prey is chosen at random, and the distance from the prey is randomly chosen between 2 and 4.
            float t = 2f * MathF.PI * _rng.NextFloat();                 // Random angle.
            float r = MathF.FusedMultiplyAdd(2f, _rng.NextFloat(), 2f); // A distance between 2 and 4.

            _agentPos.X = _preyPos.X + (int)MathF.Truncate(MathF.Cos(t) * r);
            _agentPos.Y = _preyPos.Y + (int)MathF.Truncate(MathF.Sin(t) * r);
        }
Пример #2
0
        public void CreateGenome()
        {
            var metaNeatGenome = new MetaNeatGenome <double>(
                inputNodeCount: 10,
                outputNodeCount: 20,
                isAcyclic: true,
                activationFn: new NeuralNets.Double.ActivationFunctions.ReLU());

            var genomeBuilder = NeatGenomeBuilderFactory <double> .Create(metaNeatGenome);

            int count = 100;
            NeatPopulation <double> pop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 0.1, count, RandomDefaults.CreateRandomSource());

            var generationSeq = new Int32Sequence();

            var strategy = new UniformCrossoverReproductionStrategy <double>(
                pop.MetaNeatGenome.IsAcyclic,
                0.02,
                genomeBuilder,
                pop.GenomeIdSeq, generationSeq);

            IRandomSource rng = RandomDefaults.CreateRandomSource(0);

            var cyclicGraphCheck = new CyclicGraphCheck();

            for (int i = 0; i < 1000; i++)
            {
                // Randomly select two parents from the population.
                var genome1 = pop.GenomeList[rng.Next(count)];
                var genome2 = pop.GenomeList[rng.Next(count)];

                var childGenome = strategy.CreateGenome(genome1, genome2, rng);

                // The connection genes should be sorted.
                Assert.True(SortUtils.IsSortedAscending <DirectedConnection>(childGenome.ConnectionGenes._connArr));

                // The child genome should describe an acyclic graph, i.e. the new connection should not have
                // formed a cycle in the graph.
                var digraph = childGenome.DirectedGraph;
                Assert.False(cyclicGraphCheck.IsCyclic(digraph));

                // The child genome node IDs should be a superset of those from parent1 + parent2.
                var childNodeIdSet = GetNodeIdSet(childGenome);
                var parentIdSet    = GetNodeIdSet(genome1);
                parentIdSet.IntersectWith(GetNodeIdSet(genome2));

                Assert.True(childNodeIdSet.IsSupersetOf(parentIdSet));
            }
        }
 /// <summary>
 /// Gets the next 64 random bits.
 /// </summary>
 public void Next(ref ValueUnion value)
 {
     lock (syncRoot)
     {
         source.Next(ref value);
     }
 }
Пример #4
0
 /// <summary>
 /// Initialise an array with random integers.
 /// </summary>
 /// <param name="keys">The array to initialise.</param>
 /// <param name="rng">Random number generator.</param>
 public static void InitRandom(Span <int> keys, IRandomSource rng)
 {
     for (int i = 0; i < keys.Length; i++)
     {
         keys[i] = rng.Next();
     }
 }
Пример #5
0
        /// <summary>
        /// Take multiple samples from a set of possible outcomes with equal probability, i.e. a uniform discrete distribution,
        /// with replacement, i.e. any given value will only occur once at most in the set of samples
        /// </summary>
        /// <param name="numberOfOutcomes">The number of possible outcomes per sample.</param>
        /// <param name="sampleArr">An array to fill with samples.</param>
        /// <param name="rng">A source of randomness.</param>
        public static void SampleUniformWithoutReplacement(int numberOfOutcomes, int[] sampleArr, IRandomSource rng)
        {
            if (sampleArr.Length > numberOfOutcomes)
            {
                throw new ArgumentException("sampleArr length must be less then or equal to numberOfOutcomes.");
            }

            // Create an array of indexes, one index per possible choice.
            int[] indexArr = new int[numberOfOutcomes];
            for (int i = 0; i < numberOfOutcomes; i++)
            {
                indexArr[i] = i;
            }

            // Sample loop.
            for (int i = 0; i < sampleArr.Length; i++)
            {
                // Select an index at random.
                int idx = rng.Next(i, numberOfOutcomes);

                // Swap elements i and idx.
                Swap(indexArr, i, idx);
            }

            // Copy the samples into the result array.
            for (int i = 0; i < sampleArr.Length; i++)
            {
                sampleArr[i] = indexArr[i];
            }
        }
        private static string Encode_WriteFragments(byte[] buf, int count, IRandomSource rng)
        {
            using (MemoryStream ms = new(buf.Length))
            {
                using (Base64EncodingOutputStream base64Strm = new(ms, Encoding.UTF8))
                {
                    int idx    = 0;
                    int remain = count;

                    while (remain > 0)
                    {
                        int len = Math.Min(rng.Next(256), remain);
                        base64Strm.Write(buf, idx, len);
                        idx    += len;
                        remain -= len;
                    }
                }

                ms.Position = 0;

                using StreamReader sr = new(ms, Encoding.UTF8);
                string base64Str = sr.ReadToEnd();
                return(base64Str);
            }
        }
Пример #7
0
 private static void InitRandomValues(Span <int> span, IRandomSource rng)
 {
     for (int i = 0; i < span.Length; i++)
     {
         span[i] = rng.Next();
     }
 }
Пример #8
0
 /// <summary>
 /// Initialise an array with random integers.
 /// </summary>
 /// <param name="arr">The array to initialise.</param>
 /// <param name="rng">Random number generator.</param>
 public static void InitRandom(int[] arr, IRandomSource rng)
 {
     for (int i = 0; i < arr.Length; i++)
     {
         arr[i] = rng.Next();
     }
 }
Пример #9
0
        /// <summary>Generates a sequence of integral numbers within a specified range and in random order.</summary>
        /// <param name="start">The value of the first integer in the sequence.</param>
        /// <param name="count">The number of sequential integers to generate.</param>
        /// <returns>A new IEnumerable{int}.</returns>
        public static IEnumerable <int> RangeRandomOrder(int start, int count, IRandomSource rng)
        {
            long numl = (long)start + (long)count - 1L;

            if (count < 0 || numl > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            // Create an array of all indexes to be yielded.
            int[] arr = new int[count];
            for (int i = 0; i < count; i++)
            {
                arr[i] = start + i;
            }

            // Yield all values in turn, applying a Fisher–Yates shuffle as we go in order to randomize the yield order.
            // See https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
            for (int i = count - 1; i > 0; i--)
            {
                int swapIdx = rng.Next(i + 1);
                int tmp     = arr[swapIdx];
                arr[swapIdx] = arr[i];
                arr[i]       = tmp;

                yield return(arr[i]);
            }

            // Yield final value.
            yield return(arr[0]);
        }
        /// <summary>
        /// Construct with the given distribution and a random source.
        /// </summary>
        /// <param name="max">Maximum absolute value.</param>
        /// <param name="signed">Indicates if the distribution interval includes negative values.</param>
        /// <param name="rng">Random source.</param>
        public Int32UniformDistributionSampler(int max, bool signed, IRandomSource rng)
        {
            _max    = max;
            _signed = signed;
            _rng    = rng;

            // Note. We predetermine which of these two function variants to use at construction time,
            // thus avoiding a branch on each invocation of Sample() (i.e. this is a micro-optimization).
            if (signed)
            {
                _sampleFn = (r) => _rng.Next(-max, max);
            }
            else
            {
                _sampleFn = (r) => _rng.Next(max);
            }
        }
Пример #11
0
 private static int[] CreateRandomConnectionIdArray(int length, IRandomSource rng)
 {
     int[] arr = new int[length];
     for (int i = 0; i < length; i++)
     {
         arr[i] = rng.Next(length);
     }
     return(arr);
 }
Пример #12
0
        public void LongRandomArrays()
        {
            IRandomSource rng = RandomDefaults.CreateRandomSource(0);

            for (int i = 0; i < 100; i++)
            {
                int length = rng.Next(200000);
                LongRandomArraysInner(length, rng);
            }
        }
Пример #13
0
        private static int[] CreateRandomArray(int len, IRandomSource rng)
        {
            var arr = new int[len];

            for (int i = 0; i < len; i++)
            {
                arr[i] = rng.Next(int.MinValue, int.MaxValue);
            }
            return(arr);
        }
        public Species <T>[] InitialiseSpecies(
            IList <NeatGenome <T> > genomeList,
            int speciesCount,
            IRandomSource rng)
        {
            // Create an array of seed genomes, i.e. each of these genomes will become the initial
            // seed/centroid of one species.
            var seedGenomeList = new List <NeatGenome <T> >(speciesCount);

            // Create a list of genomes to select and remove seed genomes from.
            var remainingGenomes = new List <NeatGenome <T> >(genomeList);

            // Select first genome at random.
            seedGenomeList.Add(GetAndRemove(remainingGenomes, rng.Next(remainingGenomes.Count)));

            // Select all other seed genomes using k-means++ method.
            for (int i = 1; i < speciesCount; i++)
            {
                var seedGenome = GetSeedGenome(seedGenomeList, remainingGenomes, rng);
                seedGenomeList.Add(seedGenome);
            }

            // Create an array of species initialised with the chosen seed genomes.

            // Each species is created with an initial capacity that will reduce the need for memory
            // reallocation but that isn't too wasteful of memory.
            int initialCapacity = (genomeList.Count * 2) / speciesCount;

            var speciesArr = new Species <T> [speciesCount];

            for (int i = 0; i < speciesCount; i++)
            {
                var seedGenome = seedGenomeList[i];
                speciesArr[i] = new Species <T>(i, seedGenome.ConnectionGenes, initialCapacity);
                speciesArr[i].GenomeList.Add(seedGenome);
            }

            // Allocate all other genomes to the species centroid they are nearest too.
            Parallel.ForEach(remainingGenomes, _parallelOptions, genome =>
            {
                var nearestSpeciesIdx = GetNearestSpecies(_distanceMetric, genome, speciesArr);
                var nearestSpecies    = speciesArr[nearestSpeciesIdx];

                lock (nearestSpecies.GenomeList) {
                    nearestSpecies.GenomeList.Add(genome);
                }
            });

            // Recalc species centroids.
            Parallel.ForEach(speciesArr, _parallelOptions, species => {
                species.Centroid = _distanceMetric.CalculateCentroid(species.GenomeList.Select(genome => genome.ConnectionGenes));
            });

            return(speciesArr);
        }
Пример #15
0
        static double BuildDouble(IRandomSource source)
        {
            double value;

            do
            {
                value = BitConverter.ToDouble(source.Next(8), 0);
            }while(double.IsNaN(value) || double.IsInfinity(value));

            return(value);
        }
Пример #16
0
        static float BuildFloat(IRandomSource source)
        {
            float value;

            do
            {
                value = BitConverter.ToSingle(source.Next(4), 0);
            }while(float.IsNaN(value) || float.IsInfinity(value));

            return(value);
        }
Пример #17
0
        static decimal BuildDecimal(IRandomSource source)
        {
            byte scale = (byte)(source.Next(1)[0] % 29);
            bool sign  = BuildBoolean(source);

            return(new decimal(
                       BuildInt(source),
                       BuildInt(source),
                       BuildInt(source),
                       sign,
                       scale));
        }
Пример #18
0
        /// <summary>
        /// Randomly shuffles a sub-span of items within a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <param name="startIdx">The index of the first item in the segment.</param>
        /// <param name="endIdx">The index of the last item in the segment, i.e. endIdx is inclusive; the item at endIdx will participate in the shuffle.</param>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng, int startIdx, int endIdx)
        {
            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

            for (int i = endIdx; i > startIdx; i--)
            {
                int swapIdx = startIdx + rng.Next((i - startIdx) + 1);
                T   tmp     = list[swapIdx];
                list[swapIdx] = list[i];
                list[i]       = tmp;
            }
        }
Пример #19
0
        /// <summary>
        /// Randomly shuffles the items of a span.
        /// </summary>
        /// <param name="span">The span to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <typeparam name="T">The span element type.</typeparam>
        public static void Shuffle <T>(Span <T> span, IRandomSource rng)
        {
            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

            for (int i = span.Length - 1; i > 0; i--)
            {
                int swapIdx = rng.Next(i + 1);
                T   tmp     = span[swapIdx];
                span[swapIdx] = span[i];
                span[i]       = tmp;
            }
        }
Пример #20
0
        /// <summary>
        /// Randomly shuffles items within a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng)
        {
            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

            for (int i = list.Count - 1; i > 0; i--)
            {
                int swapIdx = rng.Next(i + 1);
                T   tmp     = list[swapIdx];
                list[swapIdx] = list[i];
                list[i]       = tmp;
            }
        }
Пример #21
0
 /// <summary>
 /// Randomly shuffles items within a list.
 /// </summary>
 /// <param name="list">The list to shuffle.</param>
 /// <param name="rng">Random number generator.</param>
 public static void Shuffle <T>(IList <T> list, IRandomSource rng)
 {
     // This approach was suggested by Jon Skeet in a dotNet newsgroup post and
     // is also the technique used by the OpenJDK. The use of rnd.Next(i+1) introduces
     // the possibility of swapping an item with itself, I suspect the reasoning behind this
     // has to do with ensuring the probability of each possible permutation is approximately equal.
     for (int i = list.Count - 1; i > 0; i--)
     {
         int swapIndex = rng.Next(i + 1);
         T   tmp       = list[swapIndex];
         list[swapIndex] = list[i];
         list[i]         = tmp;
     }
 }
Пример #22
0
        private bool TryGetConnectionInner(
            NeatGenome <T> parent,
            IRandomSource rng,
            out DirectedConnection conn,
            out int insertIdx)
        {
            int inputCount  = _metaNeatGenome.InputNodeCount;
            int outputCount = _metaNeatGenome.OutputNodeCount;
            int hiddenCount = parent.HiddenNodeIdArray.Length;

            // Select a source node at random.
            // Note. this can be any node (input, output or hidden).
            int totalNodeCount = parent.MetaNeatGenome.InputOutputNodeCount + hiddenCount;
            int srcId          = GetNodeIdFromIndex(parent, rng.Next(totalNodeCount));

            // Select a target node at random.
            // Note. This cannot be an input node (so must be a hidden or output node).
            int outputHiddenCount = outputCount + hiddenCount;
            int tgtId             = GetNodeIdFromIndex(parent, inputCount + rng.Next(outputHiddenCount));

            // Test if the chosen connection already exists.
            // Note. Connection genes are always sorted by sourceId then targetId, so we can use a binary search to
            // find an existing connection in O(log(n)) time.
            conn = new DirectedConnection(srcId, tgtId);

            if ((insertIdx = Array.BinarySearch(parent.ConnectionGenes._connArr, conn)) < 0)
            {
                // The proposed new connection does not already exist, therefore we can use it.
                // Get the position in parent.ConnectionGeneArray that the new connection should be inserted at (to maintain sort order).
                insertIdx = ~insertIdx;
                return(true);
            }

            conn      = default;
            insertIdx = default;
            return(false);
        }
Пример #23
0
        public static void CloneTest(IRandomSource source)
        {
            new Generator(source, "CloneTest").UInt64();
            var clone = source.Clone();

            Assert.IsNotNull(source);
            var sourceNext = new ValueUnion();
            var cloneNext  = new ValueUnion();

            for (int i = 0; i < 100; i++)
            {
                source.Next(ref sourceNext);
                clone.Next(ref cloneNext);
                Assert.AreEqual(sourceNext.UInt64_0, cloneNext.UInt64_0);
            }
        }
Пример #24
0
        /// <summary>
        /// Randomly shuffles a sub-span of items within a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <param name="startIdx">The index of the first item in the segment.</param>
        /// <param name="endIdx">The index of the last item in the segment, i.e. endIdx is inclusive; the item at endIdx will participate in the shuffle.</param>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng, int startIdx, int endIdx)
        {
            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

            // Determine how many items in the list will be being shuffled
            int itemCount = (endIdx - startIdx);

            for (int i = endIdx; i > startIdx; i--)
            {
                int swapIdx = startIdx + rng.Next((i - startIdx) + 1);
                T   tmp     = list[swapIdx];
                list[swapIdx] = list[i];
                list[i]       = tmp;
            }
        }
Пример #25
0
        /// <summary>
        /// Randomly shuffles a sub-span of items within a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <param name="startIdx">The index of the first item in the segment.</param>
        /// <param name="endIdx">The index of the last item in the segment, i.e. endIdx is inclusive; the item at endIdx will participate in the shuffle.</param>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng, int startIdx, int endIdx)
        {
            // Determine how many items in the list will be being shuffled
            int itemCount = (endIdx - startIdx);

            // This approach was suggested by Jon Skeet in a dotNet newsgroup post and
            // is also the technique used by the OpenJDK. The use of rnd.Next(i+1) introduces
            // the possibility of swapping an item with itself, I suspect the reasoning behind this
            // has to do with ensuring the probability of each possible permutation is approximately equal.
            for (int i = endIdx; i > startIdx; i--)
            {
                int swapIndex = startIdx + rng.Next((i - startIdx) + 1);
                T   tmp       = list[swapIndex];
                list[swapIndex] = list[i];
                list[i]         = tmp;
            }
        }
Пример #26
0
        public static void TestSpeciateAdd(
            int popSize,
            int inputNodeCount,
            int outputNodeCount,
            double connectionsProportion,
            IDistanceMetric <double> distanceMetric,
            ISpeciationStrategy <NeatGenome <double>, double> speciationStrategy,
            IRandomSource rng,
            bool validateNearestSpecies = true)
        {
            // Create population.
            NeatPopulation <double> neatPop = CreateNeatPopulation(popSize, inputNodeCount, outputNodeCount, connectionsProportion);

            // Split the population into three.
            int popSize1 = popSize / 3;
            int popSize2 = popSize / 3;
            int popSize3 = popSize - (popSize1 + popSize2);

            var genomeList1 = neatPop.GenomeList.GetRange(0, popSize1);
            var genomeList2 = neatPop.GenomeList.GetRange(popSize1, popSize2);
            var genomeList3 = neatPop.GenomeList.GetRange(popSize1 + popSize2, popSize3);

            for (int i = 0; i < 6; i++)
            {
                int speciesCount = rng.Next(1, (neatPop.GenomeList.Count / 4) + 1);

                var fullGenomeList = new List <NeatGenome <double> >(genomeList1);

                // Invoke speciation strategy, and run tests
                var speciesArr = speciationStrategy.SpeciateAll(genomeList1, speciesCount, rng);
                ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies);

                // Add second batch of genomes, and re-run tests.
                speciationStrategy.SpeciateAdd(genomeList2, speciesArr, rng);

                fullGenomeList.AddRange(genomeList2);
                ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies);

                // Add third batch of genomes, and re-run tests.
                speciationStrategy.SpeciateAdd(genomeList3, speciesArr, rng);

                fullGenomeList.AddRange(genomeList3);
                ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies);
            }
        }
Пример #27
0
        /// <summary>Generates a sequence of integral numbers within a specified range and in random order.</summary>
        /// <param name="start">The value of the first integer in the sequence.</param>
        /// <param name="count">The number of sequential integers to generate.</param>
        /// <param name="rng">Random source.</param>
        /// <returns>A new IEnumerable{int}.</returns>
        public static IEnumerable <int> RangeRandomOrder(int start, int count, IRandomSource rng)
        {
            if (count < 0 || (((long)start + count) - 1L) > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            // Initialise an array of all indexes to be yielded.
            int[] arr = ArrayPool <int> .Shared.Rent(count);

            try
            {
                for (int i = 0; i < count; i++)
                {
                    arr[i] = start + i;
                }

                // Yield all values in turn, applying a Fisher–Yates shuffle as we go in order to randomize the yield order.
                // See https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
                for (int i = count - 1; i > 0; i--)
                {
                    // Select at random from the remaining available slots.
                    int selectIdx = rng.Next(i + 1);

                    // Store the yield value.
                    int tmp = arr[selectIdx];

                    // Replace the selected slot value with a value that has not yet been selected.
                    // This is half of the Fisher–Yates swap, but since we don't need the final
                    // shuffled array we can omit moving the yielded value into its new slot.
                    arr[selectIdx] = arr[i];

                    // Yield the value from the randomly selected slot.
                    yield return(tmp);
                }

                // Yield final value.
                yield return(arr[0]);
            }
            finally
            {
                ArrayPool <int> .Shared.Return(arr);
            }
        }
Пример #28
0
        /// <summary>
        /// Randomly shuffles a sub-span of items within a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <param name="startIdx">The index of the first item in the segment.</param>
        /// <param name="endIdx">The index of the last item in the segment, i.e. endIdx is inclusive; the item at endIdx will participate in the shuffle.</param>
        /// <typeparam name="T">The list element type.</typeparam>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng, int startIdx, int endIdx)
        {
            // Invoke the faster Span overload if the IList is an array.
            if (list is T[] arr)
            {
                SortUtils.Shuffle(arr.AsSpan().Slice(startIdx, (endIdx - startIdx) + 1), rng);
                return;
            }

            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
            for (int i = endIdx; i > startIdx; i--)
            {
                int swapIdx = startIdx + rng.Next((i - startIdx) + 1);
                T   tmp     = list[swapIdx];
                list[swapIdx] = list[i];
                list[i]       = tmp;
            }
        }
Пример #29
0
        /// <summary>
        /// Randomly shuffles the items of a list.
        /// </summary>
        /// <param name="list">The list to shuffle.</param>
        /// <param name="rng">Random number generator.</param>
        /// <typeparam name="T">The list element type.</typeparam>
        public static void Shuffle <T>(IList <T> list, IRandomSource rng)
        {
            // Invoke the faster Span overload if the IList is an array.
            if (list is T[] arr)
            {
                SortUtils.Shuffle <T>(arr, rng);
                return;
            }

            // Fisher–Yates shuffle.
            // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

            for (int i = list.Count - 1; i > 0; i--)
            {
                int swapIdx = rng.Next(i + 1);
                T   tmp     = list[swapIdx];
                list[swapIdx] = list[i];
                list[i]       = tmp;
            }
        }
        /// <summary>
        /// Create a new child genome from a given parent genome.
        /// </summary>
        /// <param name="parent">The parent genome.</param>
        /// <param name="rng">Random source.</param>
        /// <returns>A new child genome.</returns>
        public NeatGenome <T>?CreateChildGenome(NeatGenome <T> parent, IRandomSource rng)
        {
            // We require at least two connections in the parent, i.e. we avoid creating genomes with
            // no connections, which would be pointless.
            if (parent.ConnectionGenes.Length < 2)
            {
                return(null);
            }

            // Select a gene at random to delete.
            var parentConnArr   = parent.ConnectionGenes._connArr;
            var parentWeightArr = parent.ConnectionGenes._weightArr;
            int parentLen       = parentConnArr.Length;
            int deleteIdx       = rng.Next(parentLen);

            // Create the child genome's ConnectionGenes object.
            int childLen  = parentLen - 1;
            var connGenes = new ConnectionGenes <T>(childLen);
            var connArr   = connGenes._connArr;
            var weightArr = connGenes._weightArr;

            // Copy genes up to deleteIdx.
            Array.Copy(parentConnArr, connArr, deleteIdx);
            Array.Copy(parentWeightArr, weightArr, deleteIdx);

            // Copy remaining genes (if any).
            Array.Copy(parentConnArr, deleteIdx + 1, connArr, deleteIdx, childLen - deleteIdx);
            Array.Copy(parentWeightArr, deleteIdx + 1, weightArr, deleteIdx, childLen - deleteIdx);

            // Get an array of hidden node IDs.
            var hiddenNodeIdArr = GetHiddenNodeIdArray(parent, deleteIdx, connArr);

            // Create and return a new genome.
            return(_genomeBuilder.Create(
                       _genomeIdSeq.Next(),
                       _generationSeq.Peek,
                       connGenes,
                       hiddenNodeIdArr));
        }