public static PathChosen NearestNeighbor(CityCollection cities) { PathChosen result = new PathChosen(cities); int numAvailable = cities.Count - 1; List <City> usedCities = new List <City>(); // initialize empty City currentCity = cities[0]; usedCities.Add(currentCity); while (numAvailable > 0) { // find the next closest City closest = cities.NearestTo(currentCity.X, currentCity.Y, usedCities); // add to our path result.AddNextCity(closest); currentCity = closest; // remember that we've seen this usedCities.Add(closest); numAvailable--; } return(result); }
public PathChosen(CityCollection setOfCities) { // keep a reference to the cities Cities = setOfCities; // and a corresponding list of indexes that specifies the path to take CityIndexes = new List <int>(); }
public CandidateSolution(PathChosen existingPath) { path = new PathChosen(existingPath); cities = path.Cities; }
public CandidateSolution(CityCollection availableCities) { cities = availableCities; path = new PathChosen(cities); path.CreateRandomOrdering(); }
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); }