/// <summary> /// Draw just the list of cities. /// </summary> /// <param name="cityList">The list of cities to draw.</param> private void DrawCityList(Cities cityList) { Image cityImage = new Bitmap(tourDiagram.Width, tourDiagram.Height); Graphics graphics = Graphics.FromImage(cityImage); if (pic_d) { graphics.DrawImage(pic, ulCorner); } foreach (City city in cityList) { // Draw a circle for the city. graphics.DrawEllipse(Pens.Red, city.Location.X - 2, city.Location.Y - 2, 5, 5); } this.tourDiagram.Image = cityImage; updateCityCount(); }
/// <summary> /// Draw just the list of cities. /// </summary> /// <param name="cityList">The list of cities to draw.</param> private void DrawCityList(Cities cityList) { Image cityImage = new Bitmap(tourDiagram.Width, tourDiagram.Height); Graphics graphics = Graphics.FromImage(cityImage); int City_num = 1; foreach (City city in cityList) { // Draw a circle for the city. graphics.DrawString(City_num.ToString(), drawFont, drawBrush, city.Location.X + 3, city.Location.Y + 3); graphics.DrawEllipse(Pens.Black, city.Location.X - 2, city.Location.Y - 2, 5, 5); City_num += 1; } this.tourDiagram.Image = cityImage; updateCityCount(); }
/// <summary> /// Determine fitness /// </summary> public void DetermineFitness(Cities cities) { Fitness = 0; int lastCity = 0; int nextCity = this[0].Connection1; foreach (Link link in this) { Fitness += cities[lastCity].Distances[nextCity]; if (lastCity != this[nextCity].Connection1) { lastCity = nextCity; nextCity = this[nextCity].Connection1; } else { lastCity = nextCity; nextCity = this[nextCity].Connection2; } } }
/// <summary> /// Perform the crossover operation on 2 parent tours to create a new child tour. /// This function should be called twice to make the 2 children. /// In the second call, the parent parameters should be swapped. /// </summary> /// <param name="parent1">The first parent tour.</param> /// <param name="parent2">The second parent tour.</param> /// <param name="cityList">The list of cities in this tour.</param> /// <param name="rand">Random number generator. We pass around the same random number generator, so that results between runs are consistent.</param> /// <returns>The child tour.</returns> public static Tour Crossover(Tour parent1, Tour parent2, Cities cityList, Random rand) { Tour child = new Tour(cityList.Count); // the new tour we are making int[] cityUsage = new int[cityList.Count]; // how many links 0-2 that connect to this city int city; // for loop variable int nextCity; // the other city in this link for (city = 0; city < cityList.Count; city++) { cityUsage[city] = 0; } // Take all links that both parents agree on and put them in the child for (city = 0; city < cityList.Count; city++) { if (cityUsage[city] < 2) { if (parent1[city].Connection1 == parent2[city].Connection1) { nextCity = parent1[city].Connection1; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection2 == parent2[city].Connection2) { nextCity = parent1[city].Connection2; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection1 == parent2[city].Connection2) { nextCity = parent1[city].Connection1; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection2 == parent2[city].Connection1) { nextCity = parent1[city].Connection2; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } } } // The parents don't agree on whats left, so we will alternate between using // links from parent 1 and then parent 2. for (city = 0; city < cityList.Count; city++) { if (cityUsage[city] < 2) { if (city % 2 == 1) // we prefer to use parent 1 on odd cities { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); if (nextCity == -1) // but if thats not possible we still go with parent 2 { nextCity = findNextCity(parent2, child, cityList, cityUsage, city);; } } else // use parent 2 instead { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); } } if (nextCity != -1) { joinCities(child, cityUsage, city, nextCity); // not done yet. must have been 0 in above case. if (cityUsage[city] == 1) { if (city % 2 != 1) // use parent 1 on even cities { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); if (nextCity == -1) // use parent 2 instead { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); } } else // use parent 2 { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); } } if (nextCity != -1) { joinCities(child, cityUsage, city, nextCity); } } } } } // Remaining links must be completely random. // Parent's links would cause multiple disconnected loops. for (city = 0; city < cityList.Count; city++) { while (cityUsage[city] < 2) { do { nextCity = rand.Next(cityList.Count); // pick a random city, until we find one we can link to } while (!testConnectionValid(child, cityList, cityUsage, city, nextCity)); joinCities(child, cityUsage, city, nextCity); } } return(child); }
/// <summary> /// Starts the TSP algorithm. /// To stop before all generations are calculated, set <see cref="Halt"/> to true. /// </summary> /// <param name="populationSize">Number of random tours to create before starting the algorithm.</param> /// <param name="maxGenerations">Number of times to perform the crossover operation before stopping.</param> /// <param name="groupSize">Number of tours to examine in each generation. Top 2 are chosen as the parent tours whose children replace the worst 2 tours in the group.</param> /// <param name="mutation">Odds that a child tour will be mutated..</param> /// <param name="iterationForConverge">Iteration for converge...</param> /// <param name="seed">Seed for the random number generator.</param> /// <param name="chanceToUseCloseCity">The odds (out of 100) that a city that is known to be close will be used in any given link.</param> /// <param name="cityList">List of cities in the tour.</param> public void Begin(int populationSize, int maxGenerations, int groupSize, int mutation, int iterationForConverge, int seed, int chanceToUseCloseCity, Cities cityList) { rand = new Random(seed); this.cityList = cityList; population = new Population(); population.CreateRandomPopulation(populationSize, cityList, rand, chanceToUseCloseCity); displayTour(population.BestTour, 0, false); bool foundNewBestTour = false; TspForm tspform = new TspForm(); int ItterForStop = 0; int Waiter = 0; for (generation = 0; generation < maxGenerations; generation++) { Waiter += 1; if (Waiter >= 100) { if (TspForm.iteration == 0 || generation >= 50 && generation <= maxGenerations / 100) { TspForm.iteration = generation; } if (TspForm.iteration != generation) { double stop_work = TspForm.iteration - generation / 1.4; if (stop_work <= 0) { ItterForStop += 1; } } if (ItterForStop == iterationForConverge) { Halt = true;//Break the algorithm if we found the best tour } } if (Halt) { break; // GUI has requested we exit. } foundNewBestTour = makeChildren(groupSize, mutation); if (foundNewBestTour) { displayTour(population.BestTour, generation, false); } } displayTour(population.BestTour, generation, true); }
/// <summary> /// Starts the TSP algorithm. /// To stop before all generations are calculated, set <see cref="Halt"/> to true. /// </summary> /// <param name="populationSize">Number of random tours to create before starting the algorithm.</param> /// <param name="maxGenerations">Number of times to perform the crossover operation before stopping.</param> /// <param name="groupSize">Number of tours to examine in each generation. Top 2 are chosen as the parent tours whose children replace the worst 2 tours in the group.</param> /// <param name="mutation">Odds that a child tour will be mutated..</param> /// <param name="seed">Seed for the random number generator.</param> /// <param name="chanceToUseCloseCity">The odds (out of 100) that a city that is known to be close will be used in any given link.</param> /// <param name="cityList">List of cities in the tour.</param> public void Begin(int populationSize, int maxGenerations, int groupSize, int mutation, int seed, int chanceToUseCloseCity, Cities cityList, int Col) { rand = new Random(seed); this.cityList = cityList; population = new Population(); population.CreateRandomPopulation(populationSize, cityList, rand, chanceToUseCloseCity); displayTour(population.BestTour, 0, false, Col); bool foundNewBestTour = false; int generation; for (generation = 0; generation < maxGenerations; generation++) { if (Halt) { break; // GUI has requested we exit. } foundNewBestTour = makeChildren(groupSize, mutation); if (foundNewBestTour) { displayTour(population.BestTour, generation, false, Col); } } displayTour(population.BestTour, generation, true, Col); }
/// <summary> /// crossover /// </summary> public static Tour Crossover(Tour parent1, Tour parent2, Cities cityList, Random rand) { Tour child = new Tour(cityList.Count); int[] cityUsage = new int[cityList.Count]; int city; int nextCity; for (city = 0; city < cityList.Count; city++) { cityUsage[city] = 0; } for (city = 0; city < cityList.Count; city++) { if (cityUsage[city] < 2) { if (parent1[city].Connection1 == parent2[city].Connection1) { nextCity = parent1[city].Connection1; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection2 == parent2[city].Connection2) { nextCity = parent1[city].Connection2; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection1 == parent2[city].Connection2) { nextCity = parent1[city].Connection1; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } if (parent1[city].Connection2 == parent2[city].Connection1) { nextCity = parent1[city].Connection2; if (testConnectionValid(child, cityList, cityUsage, city, nextCity)) { joinCities(child, cityUsage, city, nextCity); } } } } for (city = 0; city < cityList.Count; city++) { if (cityUsage[city] < 2) { if (city % 2 == 1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent2, child, cityList, cityUsage, city);; } } else { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); } } if (nextCity != -1) { joinCities(child, cityUsage, city, nextCity); if (cityUsage[city] == 1) { if (city % 2 != 1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); } } else { nextCity = findNextCity(parent2, child, cityList, cityUsage, city); if (nextCity == -1) { nextCity = findNextCity(parent1, child, cityList, cityUsage, city); } } if (nextCity != -1) { joinCities(child, cityUsage, city, nextCity); } } } } } for (city = 0; city < cityList.Count; city++) { while (cityUsage[city] < 2) { do { nextCity = rand.Next(cityList.Count); } while (!testConnectionValid(child, cityList, cityUsage, city, nextCity)); joinCities(child, cityUsage, city, nextCity); } } return(child); }