/// <summary> /// Random select a group /// </summary> bool makeChildren(int groupSize, int mutation) { int[] tourGroup = new int[groupSize]; int tourCount, i, topTour, childPosition, tempTour; for (tourCount = 0; tourCount < groupSize; tourCount++) { tourGroup[tourCount] = rand.Next(population.Count); } for (tourCount = 0; tourCount < groupSize - 1; tourCount++) { topTour = tourCount; for (i = topTour + 1; i < groupSize; i++) { if (population[tourGroup[i]].Fitness < population[tourGroup[topTour]].Fitness) { topTour = i; } } if (topTour != tourCount) { tempTour = tourGroup[tourCount]; tourGroup[tourCount] = tourGroup[topTour]; tourGroup[topTour] = tempTour; } } bool foundNewBestTour = false; childPosition = tourGroup[groupSize - 1]; population[childPosition] = Tour.Crossover(population[tourGroup[0]], population[tourGroup[1]], cityList, rand); if (rand.Next(100) < mutation) { population[childPosition].Mutate(rand); } population[childPosition].DetermineFitness(cityList); if (population[childPosition].Fitness < population.BestTour.Fitness) { population.BestTour = population[childPosition]; foundNewBestTour = true; } childPosition = tourGroup[groupSize - 2]; population[childPosition] = Tour.Crossover(population[tourGroup[1]], population[tourGroup[0]], cityList, rand); if (rand.Next(100) < mutation) { population[childPosition].Mutate(rand); } population[childPosition].DetermineFitness(cityList); if (population[childPosition].Fitness < population.BestTour.Fitness) { population.BestTour = population[childPosition]; foundNewBestTour = true; } return(foundNewBestTour); }
/// 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. /// <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> /// Randomly select a group of tours from the population. /// The top 2 are chosen as the parent tours. /// Crossover is performed on these 2 tours. /// The childred tours from this process replace the worst 2 tours in the group. /// </summary> /// <param name="groupSize">Number of tours in this group.</param> /// <param name="mutation">Odds that a child will be mutated.</param> bool makeChildren(int groupSize, int mutation) { int[] tourGroup = new int[groupSize]; int tourCount, i, topTour, childPosition, tempTour; // pick random tours to be in the neighborhood city group // we allow for the same tour to be included twice for (tourCount = 0; tourCount < groupSize; tourCount++) { tourGroup[tourCount] = rand.Next(population.Count); } // bubble sort on the neighborhood city group for (tourCount = 0; tourCount < groupSize - 1; tourCount++) { topTour = tourCount; for (i = topTour + 1; i < groupSize; i++) { if (population[tourGroup[i]].Fitness < population[tourGroup[topTour]].Fitness) { topTour = i; } } if (topTour != tourCount) { tempTour = tourGroup[tourCount]; tourGroup[tourCount] = tourGroup[topTour]; tourGroup[topTour] = tempTour; } } bool foundNewBestTour = false; // take the best 2 tours, do crossover, and replace the worst tour with it childPosition = tourGroup[groupSize - 1]; population[childPosition] = Tour.Crossover(population[tourGroup[0]], population[tourGroup[1]], cityList, rand); if (rand.Next(100) < mutation) { population[childPosition].Mutate(rand); } population[childPosition].DetermineFitness(cityList); // now see if the first new tour has the best fitness if (population[childPosition].Fitness < population.BestTour.Fitness) { population.BestTour = population[childPosition]; foundNewBestTour = true; } // take the best 2 tours (opposite order), do crossover, and replace the 2nd worst tour with it childPosition = tourGroup[groupSize - 2]; population[childPosition] = Tour.Crossover(population[tourGroup[1]], population[tourGroup[0]], cityList, rand); if (rand.Next(100) < mutation) { population[childPosition].Mutate(rand); } population[childPosition].DetermineFitness(cityList); // now see if the second new tour has the best fitness if (population[childPosition].Fitness < population.BestTour.Fitness) { population.BestTour = population[childPosition]; foundNewBestTour = true; } return(foundNewBestTour); }
/// <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); }