private void CrossOverParents(CandidateSolution parent1, CandidateSolution parent2, out CandidateSolution child1, out CandidateSolution child2) { child1 = parent1.DeepClone(); child2 = parent2.DeepClone(); // Do we use exact copies of parents, or crossover? if (Randomizer.GetDoubleFromZeroToOne() < crossoverRate) { // determine start and end crossover points int numCities = parent1.NumCities - 1; int start = Randomizer.IntLessThan(numCities - 2); int remaining = numCities - start; int end = Randomizer.IntBetween(numCities - remaining + 1, numCities - 1); for (int i = start; i <= end; i++) { // the two values here tell us how to swap within each child int child1cityIndex = child1.Path[i]; int child2cityIndex = child2.Path[i]; if (child1cityIndex == child2cityIndex) { continue; } // get references to both children's paths var c1List = child1.Path.ToList(); var c2List = child2.Path.ToList(); // find within child1 and swap int firstAt = c1List.IndexOf(child1cityIndex); int secondAt = c1List.IndexOf(child2cityIndex); int temp = c1List[firstAt]; c1List[firstAt] = c1List[secondAt]; c1List[secondAt] = temp; // find within child2 and swap firstAt = c2List.IndexOf(child1cityIndex); secondAt = c2List.IndexOf(child2cityIndex); temp = c2List[firstAt]; c2List[firstAt] = c2List[secondAt]; c2List[secondAt] = temp; } child1.CheckValidity(); child2.CheckValidity(); } }
private CandidateSolution SelectCandidateViaTournament() { // pick N random candidates, and then return the one with the highest fitness int bestFitness = int.MinValue; CandidateSolution bestFound = null; for (int i = 0; i < tourneySize; i++) { int randomIndex = Randomizer.IntLessThan(populationSize); CandidateSolution randomSolution = currentGeneration[randomIndex]; int fitness = randomSolution.Fitness; if (fitness > bestFitness) { bestFitness = fitness; bestFound = randomSolution; } } return(bestFound); }
public PathChosen FindOptimalPath(CityCollection cities) { // create generation 0 with all randomly created possible solutions currentGeneration = new List <CandidateSolution>(populationSize); for (int i = 0; i < populationSize; i++) { currentGeneration.Add(new CandidateSolution(cities)); } int generationNumber = 1; while (true) { totalFitnessThisGeneration = 0; int bestFitnessScoreThisGeneration = System.Int32.MinValue; CandidateSolution bestSolutionThisGeneration = null; foreach (var candidate in currentGeneration) { candidate.CalculatePathLength(); } // find the longest path, which is the worst solution int longestDistance = currentGeneration.Max(c => c.PathLength); // then subtract each candidate's distance from that maximum distance foreach (var candidate in currentGeneration) { // set fitness so the shortest path is the highest value, and the worst is 0 candidate.Fitness = longestDistance - candidate.PathLength; // sum up the fitness scores for our roulette wheel selection totalFitnessThisGeneration += candidate.Fitness; if (candidate.Fitness > bestFitnessScoreThisGeneration) { bestFitnessScoreThisGeneration = candidate.Fitness; bestSolutionThisGeneration = candidate; } } // Ranked fitnesses for smoothing out selection when fitness scores vary widely //currentGeneration = currentGeneration.OrderBy(g => g.Fitness).ToList(); //int ranking = 1; //foreach (var candidate in currentGeneration) //{ // candidate.Fitness = ranking; // ranking++; //} int shortestPathThisGeneration = bestSolutionThisGeneration.PathLength; // compare this generation's best to the best that have come before it if (shortestPathThisGeneration < shortestPathAllTime) { // save the best score shortestPathAllTime = shortestPathThisGeneration; // and save the possible solution bestSolution = bestSolutionThisGeneration.DeepClone(); bestSolutionGenerationNumber = generationNumber; } else if ((generationNumber - bestSolutionGenerationNumber) > NoChangeGenerationCountForTermination) { break; } // create the next generation List <CandidateSolution> nextGeneration = new List <CandidateSolution>(); // Elitism int numElitesToAdd = (int)(elitismRate * populationSize); var theBest = currentGeneration.OrderBy(c => c.PathLength).Take(numElitesToAdd); foreach (var peakPerformer in theBest) { nextGeneration.Add(peakPerformer); } while (nextGeneration.Count < populationSize) { CandidateSolution parent1, parent2; // pick two parents based on good fitness parent1 = SelectCandidate(); parent2 = SelectCandidate(); //parent1 = SelectCandidateViaTournament(); //parent2 = SelectCandidateViaTournament(); // cross them over to generate two new children CandidateSolution child1, child2; CrossOverParents(parent1, parent2, out child1, out child2); // apply mutation to the children if needed //child1.DoSwapMutation(mutationRate); //child2.DoSwapMutation(mutationRate); child1.DoDisplacementMutation(mutationRate); child2.DoDisplacementMutation(mutationRate); // and then add them to the next generation nextGeneration.Add(child1); nextGeneration.Add(child2); } // move to the next generation currentGeneration = nextGeneration; generationNumber++; } //Debug.WriteLine(shortestPathAllTime + " found at generation " + bestSolutionGenerationNumber); return(bestSolution.Path); }