Example #1
0
    def test_solve(self):
        """Asserts an Optimization Model is correctly solved"""

        riders = parse_models(model_dicts=test_riders, cls=Rider)
        vehicles = parse_models(model_dicts=test_vehicles, cls=Vehicle)
        depots = parse_models(model_dicts=test_depots, cls=Depot)
        params = get_params()
        estimator = LinearEstimator()
        problem_builder = ProblemBuilder(params=params, estimator=estimator)
        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        problem = problem_builder.build(riders, vehicles, depots)
        model = model_builder.build(problem)
        solution = model.solve()

        self.assertTrue(solution, msg='Model could not be solved.')
        self.assertEqual(
            len(solution),
            len(vehicles),
            msg='Number of routes do not match number of vehicles.')
        stops_in_solution = [stop for route in solution for stop in route]
        for stop_ix in range(len(problem.stops)):
            self.assertIn(stop_ix,
                          stops_in_solution,
                          msg=f'Stop {stop_ix} not in solution.')
Example #2
0
    def test_build_stops(self):
        """Assert that Stops are a grouping of Riders and Depots"""

        riders = parse_models(model_dicts=test_riders, cls=Rider)
        depots = parse_models(model_dicts=test_depots, cls=Depot)
        params = get_params()
        builder = ProblemBuilder(params=params, estimator=LinearEstimator())
        stops = builder._build_stops(riders=riders,
                                     depots=depots,
                                     starts=[0, 1],
                                     ends=[0, 1])

        self.assertTrue(
            stops, msg=f'Stops could not be built from {len(riders)} riders.')
        self.assertEqual(
            len(stops),
            len(riders) + len(depots) - 1,
            msg='Number of stops differs from expected from test input.')

        for stop in stops:
            if not stop.depot_id:
                self.assertEqual(
                    stop.demand,
                    len(stop.riders),
                    msg='Stop has a demand that differs from the Riders.')
                self.assertEqual(
                    stop.location.lat,
                    mean([
                        rider.location.lat for rider in stop.riders.values()
                    ]),
                    msg='Latitude incorrectly calculated for Stop.')
                self.assertEqual(
                    stop.location.lng,
                    mean([
                        rider.location.lng for rider in stop.riders.values()
                    ]),
                    msg='Longitude incorrectly calculated for Stop.')
                first_rider = list(stop.riders.values())[0]
                self.assertEqual(
                    stop.location.extract_geohash(
                        precision=params.GEOHASH_PRECISION_GROUPING),
                    first_rider.location.extract_geohash(
                        precision=params.GEOHASH_PRECISION_GROUPING),
                    msg='Geohash for the Stop differs to that of first Rider.')

            else:
                self.assertEqual(stop.demand,
                                 0,
                                 msg='Depot stop has non-zero demand.')
Example #3
0
    def test_build(self):
        """Asserts that the Problem is built correctly"""

        params = get_params()
        estimator = LinearEstimator()
        builder = ProblemBuilder(params=params, estimator=estimator)

        riders = parse_models(model_dicts=test_riders, cls=Rider)
        vehicles = parse_models(model_dicts=test_vehicles, cls=Vehicle)
        depots = parse_models(model_dicts=test_depots, cls=Depot)
        problem = builder.build(riders, vehicles, depots)

        self.assertTrue(problem, msg='Problem could not be built.')
        self.assertEqual(
            len(problem.stops),
            len(riders) + len(depots) - 1,
            msg='Number of stops differs from expected from test input.')
        self.assertEqual(len(problem.estimations),
                         (len(riders) + len(depots) - 1)**2,
                         msg='Number of estimations incorrect.')
Example #4
0
    def test_route(self):
        """Asserts the main routing method works correctly"""

        params = get_params()
        estimator = LinearEstimator()
        problem_builder = ProblemBuilder(params=params, estimator=estimator)
        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        router = Router(problem_builder=problem_builder,
                        optimization_model_builder=model_builder)
        riders = parse_models(model_dicts=test_riders, cls=Rider)
        vehicles = parse_models(model_dicts=test_vehicles, cls=Vehicle)
        depots = parse_models(model_dicts=test_depots, cls=Depot)
        routes = router.route(riders, vehicles, depots)
        self.assertTrue(routes, msg='Routes could not be built.')

        for route in routes:
            self.assertTrue(route['vehicle_id'], msg='Route without vehicle.')
            self.assertTrue(len(route['stops']) > 1,
                            msg='Route with single stop.')
Example #5
0
    def test_parse_routes(self):
        """Asserts that Routes are correctly parsed from the Opt. solution"""

        params = get_params()
        estimator = LinearEstimator()
        problem_builder = ProblemBuilder(params=params, estimator=estimator)
        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        riders = parse_models(model_dicts=test_riders, cls=Rider)
        vehicles = parse_models(model_dicts=test_vehicles, cls=Vehicle)
        depots = parse_models(model_dicts=test_depots, cls=Depot)
        problem = problem_builder.build(riders, vehicles, depots)
        model = model_builder.build(problem)
        solution = model.solve()
        routes = Router._parse_routes(problem, solution)
        self.assertTrue(routes, msg='Routes could not be built.')

        for route in routes:
            self.assertTrue(route['vehicle_id'], msg='Route without vehicle.')
            self.assertTrue(len(route['stops']) > 1,
                            msg='Route with single stop.')
Example #6
0
    def test_post_init(self):
        """Assert the actions taken after the class is instantiated"""

        riders = parse_models(model_dicts=test_riders[0:2], cls=Rider)
        stop = Stop(riders=riders)

        self.assertEqual(stop.demand,
                         len(riders),
                         msg='Stop has demand that differs from riders.')
        self.assertEqual(
            stop.location.lat,
            mean([rider.location.lat for rider in riders.values()]),
            msg='Latitude incorrectly calculated for Stop.')
        self.assertEqual(
            stop.location.lng,
            mean([rider.location.lng for rider in riders.values()]),
            msg='Longitude incorrectly calculated for Stop.')
Example #7
0
class TestsOptimizationModelBuilder(unittest.TestCase):
    """Tests for the Optimization Model Builder class"""

    # Base Problem
    riders = parse_models(model_dicts=test_riders[0:2], cls=Rider)
    vehicles = parse_models(model_dicts=test_vehicles, cls=Vehicle)
    depots = parse_models(model_dicts=test_depots, cls=Depot)
    stops = [
        Stop(depot_id=list(depots.values())[0].depot_id,
             location=list(depots.values())[0].location),
        Stop(riders=riders)
    ]
    estimations = {(0, 0): 0., (0, 1): 85., (1, 0): 78., (1, 1): 0.}
    params = get_params()
    problem = Problem(depots=depots,
                      estimations=estimations,
                      params=params,
                      riders=riders,
                      stops=stops,
                      vehicles=vehicles,
                      starts=[0, 1],
                      ends=[0, 1])

    def test_build_manager(self):
        """Asserts that a manager is built correctly from the Problem"""

        manager = RoutingIndexManager(
            len(self.problem.stops),  # Number of locations
            len(self.problem.vehicles),  # Number of vehicles
            self.problem.starts,  # Start list of Vehicles
            self.problem.ends  # End list of Vehicles
        )
        self.assertTrue(manager, msg='Opt. Manager could not be built.')
        self.assertEqual(manager.GetNumberOfVehicles(),
                         len(self.vehicles),
                         msg='Number of vehicles in manager is incorrect.')
        self.assertEqual(manager.GetNumberOfIndices(),
                         len(self.vehicles) * 2 + len(self.stops) -
                         len(self.problem.depots),
                         msg='Number of indices in manager is incorrect.')
        solver = RoutingModel(manager)
        self.assertTrue(solver, msg='Solver could not be instantiated.')

    def test_build_search_parameters(self):
        """Asserts the heuristic search parameters are correctly created"""

        search_parameters = OptimizationModelBuilder._build_search_parameters(
            self.problem)
        self.assertTrue(search_parameters,
                        msg='Search params could not be built.')
        self.assertEqual(search_parameters.time_limit,
                         Duration(seconds=self.params.SEARCH_TIME_LIMIT),
                         msg='Time limit is incorrect in the search params.')
        self.assertEqual(
            search_parameters.solution_limit,
            self.params.SEARCH_SOLUTIONS_LIMIT,
            msg='Solutions limit is incorrect in the search params.')
        self.assertEqual(
            search_parameters.first_solution_strategy,
            FIRST_SOLUTION_STRATEGY[self.params.FIRST_SOLUTION_STRATEGY],
            msg='First solution strategy is incorrect in the search params.')
        self.assertEqual(
            search_parameters.local_search_metaheuristic,
            LOCAL_SEARCH_METAHEURISTIC[self.params.SEARCH_METAHEURISTIC],
            msg='Search metaheuristic is incorrect in the search params.')

    def test_apply_constraints_capacity_constraint(self):
        """Asserts constraints are read correctly by the solver"""

        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        problem = self.problem
        manager = RoutingIndexManager(
            len(problem.stops),  # Number of locations
            len(problem.vehicles),  # Number of vehicles
            problem.starts,  # Start list of Vehicles
            problem.ends  # End list of Vehicles
        )
        solver = RoutingModel(manager)
        model_builder._apply_constraints(problem, manager, solver)
        self.assertTrue(solver, msg='Constraints added incorrectly.')
        self.assertTrue(solver.HasDimension('capacity_constraint'),
                        msg='Capacity constraint not added.')

    def test_set_objective_function(self):
        """Asserts the objective function is added to the solver"""

        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        problem = self.problem
        manager = RoutingIndexManager(
            len(problem.stops),  # Number of locations
            len(problem.vehicles),  # Number of vehicles
            problem.starts,  # Start list of Vehicles
            problem.ends  # End list of Vehicles
        )
        solver = RoutingModel(manager)
        model_builder._set_objective_function(problem, manager, solver)
        self.assertTrue(solver, msg='Objective function set incorrectly.')

    def test_build(self):
        """Assert the Opt. model is built correctly"""

        model_builder = OptimizationModelBuilder(
            constraints=[CapacityConstraint()])
        problem = self.problem
        model = model_builder.build(problem)
        self.assertTrue(model, msg='Opt. model built incorrectly.')
        self.assertEqual(model.manager.GetNumberOfVehicles(),
                         len(self.vehicles),
                         msg='Number of vehicles in manager is incorrect.')
        self.assertEqual(model.manager.GetNumberOfIndices(),
                         len(self.vehicles) * 2 + len(self.stops) -
                         len(problem.depots),
                         msg='Number of indices in manager is incorrect.')
        self.assertTrue(model.solver, msg='Solver could not be instantiated.')
        self.assertTrue(model.search_parameters,
                        msg='Search params could not be built.')
        self.assertEqual(model.search_parameters.time_limit,
                         Duration(seconds=self.params.SEARCH_TIME_LIMIT),
                         msg='Time limit is incorrect in the search params.')
        self.assertEqual(
            model.search_parameters.solution_limit,
            self.params.SEARCH_SOLUTIONS_LIMIT,
            msg='Solutions limit is incorrect in the search params.')
        self.assertEqual(
            model.search_parameters.first_solution_strategy,
            FIRST_SOLUTION_STRATEGY[self.params.FIRST_SOLUTION_STRATEGY],
            msg='First solution strategy is incorrect in the search params.')
        self.assertEqual(
            model.search_parameters.local_search_metaheuristic,
            LOCAL_SEARCH_METAHEURISTIC[self.params.SEARCH_METAHEURISTIC],
            msg='Search metaheuristic is incorrect in the search params.')
        self.assertTrue(model.solver.HasDimension('capacity_constraint'),
                        msg='Capacity constraint not added.')