示例#1
0
        public override void Run()
        {
            int n = 4096;

            Console.WriteLine($"Starting algorithm with {n} individuals, {_amountOfRounds} rounds, " +
                              $"{_amountOfTeams} teams, and {_avgPlayersPerTeam} players per team.");

            Console.WriteLine("Initiating random population of schedules...");
            // Construct n random solutions, which are permutations of one original random set
            List <BallStarsSchedule> population = InitRandomPopulation(n)
                                                  .Select(indiv => indiv as BallStarsSchedule).ToList();

            // Evolve over generations until a sufficiently good solution is found or time runs out.
            BallStarsSchedule bestSolution = population[0];
            float             bestFitness  = bestSolution.Evaluate();
            int currentGen = 0;

            while (bestFitness != 0f && currentGen < 1000) // TODO: Include timer if necessary
            {
                Console.WriteLine($"Commencing generation {currentGen}.");

                // Create offspring by applying crossover to the existing population
                var offspring = new List <BallStarsSchedule>();

                if (_useLocalSearch)
                {
                    // Local search
                    for (int i = 0; i < population.Count; i++)
                    {
                        BallStarsSchedule clone = bestSolution.Clone();
                        offspring.Add(clone);
                    }
                }
                else if (_useCrossover)
                {
                    // Apply single-point crossover at a given cutoff point
                    for (int i = 0; i < population.Count; i += 2)
                    {
                        (BallStarsSchedule o0, BallStarsSchedule o1) =
                            population[i].Crossover(population[i + 1], _roundCrossoverCutoff);
                        offspring.Add(o0);
                        offspring.Add(o1);
                    }
                }
                else
                {
                    // Use cloning
                    foreach (var individual in population)
                    {
                        BallStarsSchedule clone = individual.Clone();
                        offspring.Add(clone);
                    }
                }

                // Mutate the offspring
                foreach (var schedule in offspring)
                {
                    if (Globals.Rand.NextDouble() < 0.8)
                    {
                        schedule.AddSportsMatchFromPool(_matchPool);
                    }
                    // schedule.GranularMutate();
                    schedule.Mutate();
                }

                // Evaluate both the population and the offspring
                population.ForEach(schedule => schedule.Evaluate());
                offspring.ForEach(schedule => schedule.Evaluate());

                // Select the best n individuals out of the population + offspring
                // population = NaiveSelection(population, offspring);
                population = TournamentSelection(population, offspring, 4);

                // Update bestFitness if possible
                foreach (var individual in population)
                {
                    float fitness = individual.Fitness;
                    if (fitness < bestFitness)
                    {
                        bestFitness  = fitness;
                        bestSolution = individual;

                        Console.WriteLine($"New best fitness: {bestFitness} (found in generation {currentGen})");
                    }
                }

                currentGen++;
            }

            // Save the best solution to a file
            bestSolution.SaveToCsv(_outputFile);
            Console.WriteLine($"Algorithm finished. The best schedule is as follows:\n{bestSolution}");
            Console.WriteLine($"The final schedule has been saved to {_outputFile}.");
        }
示例#2
0
        public void RunSimulatedAnnealing(double initialTemperature = 10, double alpha = 0.9999)
        {
            // Start off with a randomised schedule for an even amount of teams
            int eventsPerRound = _amountOfTeams / 2;
            BallStarsSchedule currentSchedule = BallStarsSchedule.Random(
                _amountOfTeams, eventsPerRound, eventsPerRound, _amountOfRounds, _matchPool, false,
                _avgPlayersPerTeam, _predefinedMatchUps
                );
            BallStarsSchedule bestSchedule           = currentSchedule;
            double            bestFitness            = currentSchedule.Evaluate();
            double            currentScheduleFitness = bestFitness;

            double minimumTemp = 0.000000001;
            double temperature = initialTemperature;
            int    iters       = 0;

            while (iters < 100000)
            {
                if (iters % 1000 == 0)
                {
                    Console.WriteLine($"Running iteration {iters}.");
                }

                // Pick a neighbour by cloning and mutating
                BallStarsSchedule neighbour = currentSchedule.Clone();
                neighbour.LocalSearchMutate(_matchPool);
                neighbour.Evaluate();

                // Always accept better solutions
                if (neighbour.Fitness < currentScheduleFitness)
                {
                    // Update currently tracking schedule and fitness
                    currentScheduleFitness = neighbour.Fitness;
                    currentSchedule        = neighbour;

                    // Update best found schedule and fitness if they improved
                    if (currentScheduleFitness < bestFitness)
                    {
                        bestFitness  = currentScheduleFitness;
                        bestSchedule = currentSchedule.Clone();

                        Console.WriteLine($"New best fitness: {bestFitness} (found in iteration {iters})");
                    }
                }
                else
                {
                    // Accept worse solutions often when starting out, but not as much near termination
                    double diff           = neighbour.Fitness - currentSchedule.Fitness;
                    double acceptanceProb = 1 / (1 + Math.Exp(diff / temperature));
                    if (Globals.Rand.NextDouble() < acceptanceProb)
                    {
                        currentSchedule        = neighbour;
                        currentScheduleFitness = neighbour.Fitness;
                    }
                }

                temperature *= alpha;
                iters++;
                // TODO: Maybe add a temperature reset to get out of a local minimum
            }

            Console.WriteLine($"Algorithm finished. The best schedule is as follows:\n{bestSchedule}");
        }