def test_solution_valid_with_required_cities(self): required_cities = [self.possible_cities["Cordoba"]] max_trip_time = 14 route = [ self.possible_cities["Cordoba"], self.possible_cities["Rosario"], self.possible_cities["Ushuaia"] ] solution = Solution(origin_city=self.origin_city, cities=route, required_cities=required_cities, max_trip_time=max_trip_time) expected_total_stay_time = 6 self.assertEqual(expected_total_stay_time, solution.get_total_stay_time()) expected_total_travel_time = 1 + 1 + 3 + 3 self.assertEqual(expected_total_travel_time, solution.get_total_travel_time()) expected_total_trip_time = expected_total_stay_time + expected_total_travel_time self.assertEqual(expected_total_trip_time, solution.get_total_trip_time()) self.assertTrue(solution.is_valid_required_city()) self.assertTrue(solution.is_valid_knapsack_time()) self.assertTrue(solution.is_valid_total_trip_time()) self.assertTrue(solution.is_valid())
def test_solution_valid_with_just_origin_city(self): required_cities = [] max_trip_time = 999999 route = [] solution = Solution(origin_city=self.origin_city, cities=route, required_cities=required_cities, max_trip_time=max_trip_time) expected_total_stay_time = 0 self.assertEqual(expected_total_stay_time, solution.get_total_stay_time()) expected_total_travel_time = 0 self.assertEqual(expected_total_travel_time, solution.get_total_travel_time()) expected_total_trip_time = expected_total_stay_time + expected_total_travel_time self.assertEqual(expected_total_trip_time, solution.get_total_trip_time()) self.assertTrue(solution.is_valid_required_city()) self.assertTrue(solution.is_valid_knapsack_time()) self.assertTrue(solution.is_valid_total_trip_time()) self.assertTrue(solution.is_valid())
def test_solution_notequal3(self): route = [self.possible_cities["Cordoba"]] solution1 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) route = [self.possible_cities["Rosario"]] solution2 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) self.assertNotEqual(solution1, solution2)
def create_random_individual(self): cities = [] cities += self.required_cities random.shuffle(self.not_required_possible_cities) for random_city in self.not_required_possible_cities: if random_city not in cities: backup = list(cities) cities.append(random_city) solution = Solution(self.origin_city, cities, self.required_cities, self.max_trip_time) if not solution.is_valid_knapsack_time(): cities = backup continue optimizer = TSPOptimizerClosestCityStrategy(self.origin_city, cities) cities = optimizer.optimize() solution.cities = cities if not solution.is_valid_total_trip_time(): cities = backup continue solution = Solution(self.origin_city, cities, self.required_cities, self.max_trip_time) optimizer = TSPOptimizerClosestCityStrategy(self.origin_city, cities) solution.cities = optimizer.optimize() return solution
def __get_child(self, other): child_solution_cities = [] # Add required cities child_solution_cities += self.required_cities # Add cities present in both parents for city_parent_1 in self.solution.cities: if city_parent_1 in other.solution.cities: if city_parent_1 not in child_solution_cities: child_solution_cities.append(city_parent_1) # Get random sample of cities from parent 1 and add them to child if not already present parent_solution_cities = [] if len(self.solution.cities) > 0: parent_solution_cities = random.sample( self.solution.cities, random.randint(1, len(self.solution.cities))) random.shuffle(parent_solution_cities) for parent_solution_city in parent_solution_cities: if parent_solution_city in child_solution_cities: continue child_solution_cities.append(parent_solution_city) # Get random sample of cities from parent 2 and add them to child if not already present parent_solution_cities = [] if len(other.solution.cities) > 0: parent_solution_cities = random.sample( other.solution.cities, random.randint(1, len(other.solution.cities))) random.shuffle(parent_solution_cities) for parent_solution_city in parent_solution_cities: if parent_solution_city in child_solution_cities: continue child_solution_cities.append(parent_solution_city) # Get child solution child_solution = Solution(self.origin_city, child_solution_cities, self.required_cities, self.max_trip_time) # Optimize tsp optimizer = TSPOptimizerClosestCityStrategy(self.origin_city, child_solution.cities) child_solution.cities = optimizer.optimize() # Delete random cities until solution is valid while not child_solution.is_valid_total_trip_time(): self.solution_delete_city(child_solution) # Optimize the tsp part of the solution optimizer = TSPOptimizerClosestCityStrategy( self.origin_city, child_solution.cities) child_solution.cities = optimizer.optimize() child_solution.update_fitness() child_individual = Individual(self.origin_city, self.possible_cities, self.required_cities, self.max_trip_time, child_solution) return child_individual
def solve(self): best_solution_fitness = 0 best_solution_trip_time = 0 if self.should_print_stats(): self.print_stats() for x in range(1, len(self.possible_trip_cities) + 1): for cities in combinations(self.possible_trip_cities, x): self.current_iteration += 1 if self.should_print_stats(): self.print_stats() solution = Solution(self.origin_city, cities, self.required_cities, self.max_trip_time) if not solution.is_valid_knapsack_time() or not solution.is_valid_required_city(): continue # Apply construction heuristic optimizer = TSPOptimizerClosestCityStrategy(self.origin_city, solution.cities) solution.cities = optimizer.optimize() if not solution.is_valid_total_trip_time(): continue if solution.fitness > best_solution_fitness: # Update best_solution as first objective fitness is better best_solution = solution self.set_best_solution(best_solution) best_solution_fitness = solution.fitness best_solution_trip_time = solution.get_total_travel_time() elif solution.fitness == best_solution_fitness: if solution.get_total_travel_time() < best_solution_trip_time: # Update best_solution as first objective fitness is same but # second objective travel time is better best_solution = solution self.set_best_solution(best_solution) best_solution_fitness = solution.fitness best_solution_trip_time = solution.get_total_travel_time() # self.add_good_solution(solution) self.improve_solutions() # return self.best_solution, self.good_solutions return self.best_solution
def test_add_good_solution_with_good_solutions_list_not_full(self): self.strategy.max_good_solution_length = 5 route = [self.possible_cities["2"], self.possible_cities["8"]] best_solution = Solution(self.origin_city, route, [], 0) best_solution.fitness = 100 self.strategy.best_solution = best_solution good_solutions = [] route = [self.possible_cities["2"]] s1 = Solution(self.origin_city, route, [], 0) good_solutions.append(s1) route = [self.possible_cities["2"], self.possible_cities["4"], self.possible_cities["8"]] s2 = Solution(self.origin_city, route, [], 0) good_solutions.append(s2) route = [self.possible_cities["2"], self.possible_cities["5"]] s3 = Solution(self.origin_city, route, [], 0) good_solutions.append(s3) route = [self.possible_cities["6"], self.possible_cities["7"]] s4 = Solution(self.origin_city, route, [], 0) good_solutions.append(s4) route = [self.possible_cities["6"], self.possible_cities["5"]] s5 = Solution(self.origin_city, route, [], 0) good_solutions.append(s5) for s in good_solutions: s.fitness = 100 self.strategy.add_good_solution(s1) self.assertEqual(self.strategy.good_solutions[0], s1) self.strategy.add_good_solution(s2) self.assertEqual(self.strategy.good_solutions[1], s2) self.strategy.add_good_solution(s3) self.assertEqual(self.strategy.good_solutions[2], s3) self.strategy.add_good_solution(s4) self.assertEqual(self.strategy.good_solutions[3], s4) self.strategy.add_good_solution(s5) self.assertEqual(self.strategy.good_solutions[4], s5)
def is_valid(self, origin_city, required_cities, max_trip_time): if len(required_cities) == 0: return True solution = Solution(origin_city, required_cities, required_cities, max_trip_time) optimizer = TSPOptimizerClosestCityStrategy(origin_city, solution.cities) solution.cities = optimizer.optimize() if not solution.is_valid(): solution.print() print() print("NOT VALID SOLUTION WITH ONLY REQUIRED CITIES") return False return True
def test_solution_invalid_with_two_required_city_both_not_present(self): required_cities = [ self.possible_cities["Cordoba"], self.possible_cities["Rosario"] ] max_trip_time = 999999 route = [self.possible_cities["Ushuaia"]] solution = Solution(origin_city=self.origin_city, cities=route, required_cities=required_cities, max_trip_time=max_trip_time) self.assertFalse(solution.is_valid_required_city()) self.assertTrue(solution.is_valid_knapsack_time()) self.assertTrue(solution.is_valid_total_trip_time()) self.assertFalse(solution.is_valid())
def crossover(self, parent1, parent2): child_solution_cities = [] # Add required cities child_solution_cities += self.required_cities # Add cities present in both parents for city_parent_1 in parent1.cities: if city_parent_1 in parent2.cities: if city_parent_1 not in child_solution_cities: child_solution_cities.append(city_parent_1) # Get random sample of cities from parent 1 and add them to child if not already present parent_solution_cities = [] if len(parent1.cities) > 0: parent_solution_cities = random.sample(parent1.cities, random.randint(1, len(parent1.cities))) random.shuffle(parent_solution_cities) for parent_solution_city in parent_solution_cities: if parent_solution_city in child_solution_cities: continue child_solution_cities.append(parent_solution_city) # Get random sample of cities from parent 2 and add them to child if not already present parent_solution_cities = [] if len(parent2.cities) > 0: parent_solution_cities = random.sample(parent2.cities, random.randint(1, len(parent2.cities))) random.shuffle(parent_solution_cities) for parent_solution_city in parent_solution_cities: if parent_solution_city in child_solution_cities: continue child_solution_cities.append(parent_solution_city) # Get child solution child_solution = Solution(self.origin_city, child_solution_cities, self.required_cities, self.max_trip_time) return child_solution
def get_valid_solution(self): while True: cities = random.sample( self.possible_trip_cities, random.randint(1, len(self.possible_trip_cities))) random.shuffle(cities) solution = Solution(self.origin_city, cities, self.required_cities, self.max_trip_time) if not solution.is_valid_knapsack_time( ) or not solution.is_valid_required_city(): continue optimizer = TSPOptimizerClosestCityStrategy( self.origin_city, solution.cities) solution.cities = optimizer.optimize() if solution.is_valid_total_trip_time(): return solution
def create_random_solution(self): while True: cities = [] cities += self.required_cities sample_size = random.randint(1, len(self.possible_cities)) random_sample_cities = random.sample(self.possible_cities, sample_size) for random_city in random_sample_cities: if random_city not in cities: cities.append(random_city) random.shuffle(cities) solution = Solution(self.origin_city, cities, self.required_cities, self.max_trip_time) if not solution.is_valid_knapsack_time( ) or not solution.is_valid_required_city(): continue optimizer = TSPOptimizerClosestCityStrategy( self.origin_city, solution.cities) solution.cities = optimizer.optimize() if solution.is_valid_total_trip_time(): return solution
def test_add_good_solution(self): self.strategy.max_good_solution_length = 5 self.strategy.good_solution_fitness_threshold = 0.8 route = [self.possible_cities["2"], self.possible_cities["8"]] best_solution = Solution(self.origin_city, route, [], 0) best_solution.fitness = 100 self.strategy.best_solution = best_solution good_solutions = [] route = [self.possible_cities["2"]] s1 = Solution(self.origin_city, route, [], 0) good_solutions.append(s1) route = [self.possible_cities["2"], self.possible_cities["4"], self.possible_cities["8"]] s2 = Solution(self.origin_city, route, [], 0) good_solutions.append(s2) route = [self.possible_cities["2"], self.possible_cities["5"]] s3 = Solution(self.origin_city, route, [], 0) good_solutions.append(s3) route = [self.possible_cities["6"], self.possible_cities["7"]] s4 = Solution(self.origin_city, route, [], 0) good_solutions.append(s4) route = [self.possible_cities["6"], self.possible_cities["5"]] s5 = Solution(self.origin_city, route, [], 0) good_solutions.append(s5) for s in good_solutions: s.fitness = 100 self.strategy.good_solutions = good_solutions route = [self.possible_cities["3"]] s6 = Solution(self.origin_city, route, [], 0) s6.fitness = 100 self.strategy.add_good_solution(s6) self.assertEqual(self.strategy.good_solutions[0], s6) self.assertEqual(self.strategy.good_solutions[1], s4) self.assertEqual(self.strategy.good_solutions[2], s5) self.assertEqual(self.strategy.good_solutions[3], s1) self.assertEqual(self.strategy.good_solutions[4], s2)
def solve(self): # Add all required cities solution = Solution(self.origin_city, list(self.required_cities), self.required_cities, self.max_trip_time) solution.update_fitness() if not solution.is_valid(): raise Exception() # Compute ratios ratios = [] for city in self.possible_trip_cities: if city in self.required_cities: continue ratios.append([city, city.value / city.stay_time]) ratios.sort(reverse=True, key=lambda x: x[1]) # Add city until knapsack is full for r in ratios: city = r[0] backup = list(solution.cities) solution.cities.append(city) solution.update_fitness() tsp_optimizer = TSPOptimizerClosestCityStrategy( self.origin_city, solution.cities) solution.cities = tsp_optimizer.optimize() if not solution.is_valid_total_trip_time(): solution.cities = backup solution.update_fitness() break self.improve_solution(solution) return solution
def test_solution_similarity(self): route = [self.possible_cities["Cordoba"]] solution1 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) route = [self.possible_cities["Rosario"]] solution2 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) route = [ self.possible_cities["Cordoba"], self.possible_cities["Rosario"] ] solution3 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) route = [ self.possible_cities["Ushuaia"], self.possible_cities["Rosario"] ] solution4 = Solution(origin_city=self.origin_city, cities=route, required_cities=[], max_trip_time=0) expected_similarity = 1 self.assertEqual(solution1.get_similarity(solution1), expected_similarity) expected_similarity = 1 self.assertEqual(solution2.get_similarity(solution2), expected_similarity) expected_similarity = 2 self.assertEqual(solution3.get_similarity(solution3), expected_similarity) expected_similarity = 2 self.assertEqual(solution4.get_similarity(solution4), expected_similarity) expected_similarity = 0 self.assertEqual(solution1.get_similarity(solution2), expected_similarity) self.assertEqual(solution2.get_similarity(solution1), expected_similarity) expected_similarity = 1 self.assertEqual(solution1.get_similarity(solution3), expected_similarity) self.assertEqual(solution3.get_similarity(solution1), expected_similarity) expected_similarity = 0 self.assertEqual(solution1.get_similarity(solution4), expected_similarity) self.assertEqual(solution4.get_similarity(solution1), expected_similarity) expected_similarity = 1 self.assertEqual(solution2.get_similarity(solution3), expected_similarity) self.assertEqual(solution3.get_similarity(solution2), expected_similarity) expected_similarity = 1 self.assertEqual(solution2.get_similarity(solution4), expected_similarity) self.assertEqual(solution4.get_similarity(solution2), expected_similarity) expected_similarity = 1 self.assertEqual(solution3.get_similarity(solution4), expected_similarity) self.assertEqual(solution4.get_similarity(solution3), expected_similarity)
def get_travel_time(self, cities): solution = Solution(self.origin_city, cities, required_cities=[], max_trip_time=0) return solution.get_total_travel_time()
def test_add_good_solution_with_fitness_not_good_enough(self): self.strategy.max_good_solution_length = 5 self.strategy.good_solution_fitness_threshold = 0.8 route = [self.possible_cities["2"], self.possible_cities["8"]] best_solution = Solution(self.origin_city, route, [], 0) best_solution.fitness = 100 self.strategy.best_solution = best_solution route = [self.possible_cities["2"]] s1 = Solution(self.origin_city, route, [], 0) s1.fitness = 79 route = [self.possible_cities["2"], self.possible_cities["4"], self.possible_cities["8"]] s2 = Solution(self.origin_city, route, [], 0) s2.fitness = 70 route = [self.possible_cities["2"], self.possible_cities["5"]] s3 = Solution(self.origin_city, route, [], 0) s3.fitness = 60 route = [self.possible_cities["6"], self.possible_cities["7"]] s4 = Solution(self.origin_city, route, [], 0) s4.fitness = 50 route = [self.possible_cities["6"], self.possible_cities["5"]] s5 = Solution(self.origin_city, route, [], 0) s5.fitness = 0 self.strategy.add_good_solution(s1) self.assertEqual(len(self.strategy.good_solutions), 0) self.strategy.add_good_solution(s2) self.assertEqual(len(self.strategy.good_solutions), 0) self.strategy.add_good_solution(s3) self.assertEqual(len(self.strategy.good_solutions), 0) self.strategy.add_good_solution(s4) self.assertEqual(len(self.strategy.good_solutions), 0) self.strategy.add_good_solution(s5) self.assertEqual(len(self.strategy.good_solutions), 0)