public Level(
                uint level,
                ProblemTower tower)
            {
                Debug.Assert(level < tower.Environment.MaxLevels);

                Index = level;
                Tower = tower;
                var env = Tower.Environment;

                Factory = env.Factory[1];                 // Use a lower priority than the factory used by broadcasting.

                var(First, Minimum, Step) = env.PoolSize;
                var maxDelta  = First - Minimum;
                var decrement = Index * Step;

                var poolCount = tower.Problem.Pools.Count;

                BestLevelFitness       = new double[poolCount][];
                BestProgressiveFitness = new double[poolCount][];
                //IsMaxLevel = level + 1 == tower.Environment.MaxLevels;

                PoolSize = decrement > maxDelta ? Minimum : (ushort)(First - decrement);
                Pool     = new BatchCreator <LevelEntry <TGenome> >(PoolSize);
            }
Esempio n. 2
0
            public Level(
                uint level,
                ProblemTower tower,
                ushort priorityLevels = 3)
            {
                Debug.Assert(level < tower.Environment.MaxLevels);

                Index = level;
                Tower = tower;
                var env     = Tower.Environment;
                var factory = env.Factory[1];

                var(First, Minimum, Step) = env.PoolSize;
                var maxDelta  = First - Minimum;
                var decrement = Index * Step;
                var poolSize  = decrement > maxDelta ? Minimum : (ushort)(First - decrement);

                Incomming = Enumerable
                            .Range(0, priorityLevels)
                            .Select(i => new ConcurrentQueue <(TGenome Genome, Fitness[] Fitness)>())
                            .ToArray();

                Processor = new TransformBlock <(TGenome Genome, Fitness[] Fitness), LevelEntry <TGenome> >(
                    async c => LevelEntry.Merge(in c, (await Tower.Problem.ProcessSampleAsync(c.Genome, Index)).ToArray()));

                var preselection
                    = new BatchBlock <LevelEntry <TGenome> >(poolSize);

                var selection
                    = new TransformBlock <LevelEntry <TGenome>[], LevelEntry <TGenome>[][]>(pool =>
                                                                                            Tower.Problem.Pools
                                                                                            .Select((p, i) => pool.OrderBy(e => e.Scores[i], ArrayComparer <double> .Descending).ToArray())
                                                                                            .ToArray());

                Processor.LinkTo(preselection);
                preselection.LinkTo(selection);
                selection.LinkTo(pools =>
                {
                    var poolCount = pools.Length;
                    var midPoint  = poolSize / 2;
                    var promoted  = new HashSet <string>();

                    var isTop = _nextLevel == null;
                    // Place champions first.
                    {
                        var problemPools = Tower.Problem.Pools;
                        for (var p = 0; p < poolCount; ++p)
                        {
                            var gf = pools[p][0].GenomeFitness;
                            if (isTop)
                            {
                                problemPools[p].Champions?.Add(gf.Genome, gf.Fitness[p]);
                                factory.EnqueueChampion(gf.Genome);                                 // Okay to enqueue more than once if the same since it may be more significant.
                                Tower.Broadcast(gf, p);
                            }
                            if (promoted.Add(gf.Genome.Hash))
                            {
                                NextLevel.Post(0, gf);
                            }
                        }
                    }

                    // Remaining top 50% (winners) should go before any losers.
                    for (var i = 1; i < midPoint; ++i)
                    {
                        for (var p = 0; p < poolCount; ++p)
                        {
                            var gf = pools[p][i].GenomeFitness;
                            if (promoted.Add(gf.Genome.Hash))
                            {
                                NextLevel.Post(1, gf);
                            }
                        }
                    }

                    // Make sure losers have thier rejection count incremented.
                    for (var i = midPoint; i < poolSize; ++i)
                    {
                        for (var p = 0; p < poolCount; ++p)
                        {
                            pools[p][i].GenomeFitness.Fitness[p].IncrementRejection();
                        }
                    }

                    // Distribute losers either back into the pool, pass them to the next level, or let them disapear (rejected).
                    var maxLoses     = Tower.Environment.MaxLevelLosses;
                    var maxRejection = Tower.Environment.MaxLossesBeforeElimination;
                    for (var i = midPoint; i < poolSize; ++i)
                    {
                        for (var p = 0; p < poolCount; ++p)
                        {
                            var loser = pools[p][i];
                            var gf    = loser.GenomeFitness;
                            loser.GenomeFitness.Fitness[p].IncrementRejection();
                            if (!promoted.Add(gf.Genome.Hash))
                            {
                                continue;
                            }

                            loser.LevelLossRecord++;
                            if (loser.LevelLossRecord > maxLoses)
                            {
                                var fitnesses = gf.Fitness;
                                if (fitnesses.Any(f => f.RejectionCount < maxRejection))
                                {
                                    NextLevel.Post(2, gf);
                                }
                                else if (Tower.Environment.Factory is GenomeFactoryBase <TGenome> f)
                                {
                                    f.MetricsCounter.Increment("Genome Rejected");
                                }
                            }
                            else
                            {
                                Debug.Assert(loser.LevelLossRecord > 0);
                                preselection.Post(loser);                                 // Didn't win, but still in the game.
                            }
                        }
                    }
                });
            }