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_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_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 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())