示例#1
0
    def print_solution(data: VehicleRoutingProblemInstance,
                       manager: RoutingIndexManager, routing: RoutingModel,
                       solution: Assignment):
        """Prints assignment on console."""
        time_dimension = routing.GetDimensionOrDie('Duration')
        total_time = 0
        for vehicle_id in range(data.num_plans_to_create):
            start_time = None
            index = routing.Start(vehicle_id)
            plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
            while not routing.IsEnd(index):
                time_var = time_dimension.CumulVar(index)
                if start_time is None:
                    start_time = solution.Min(time_var)
                plan_output += '{0} Time({1},{2}) -> '.format(
                    manager.IndexToNode(index), solution.Min(time_var),
                    solution.Max(time_var))
                index = solution.Value(routing.NextVar(index))
            time_var = time_dimension.CumulVar(index)
            plan_output += '{0} Time({1},{2})\n'.format(
                manager.IndexToNode(index), solution.Min(time_var),
                solution.Max(time_var))
            plan_output += f'Start of the route: {start_time}\n'
            plan_output += 'Time of the route: {} sec\n'.format(
                solution.Min(time_var) - start_time)
            print(plan_output)

            total_time += solution.Min(time_var) - start_time
        print('Total time of all routes: {} sec'.format(total_time))
示例#2
0
    def _set_capacity_dimension_constraints(
            self, data: VehicleRoutingProblemInstance, routing: RoutingModel,
            manager: RoutingIndexManager):

        if data.courier_capacities is None:
            return

        def demand_callback(index):
            node = manager.IndexToNode(index)
            return data.node_demands[node]

        capacity_callback = routing.RegisterUnaryTransitCallback(
            demand_callback)

        routing.AddDimensionWithVehicleCapacity(
            capacity_callback,
            0,  # waiting time
            data.courier_capacities,  # maximum distance per vehicle
            False,  # Force start cumul to zero.
            self.CAPACITY_DIMENSION_NAME)

        capacity_dimension = routing.GetDimensionOrDie(
            self.CAPACITY_DIMENSION_NAME)

        for courier_idx, start_utilization in enumerate(
                data.start_utilizations):
            node_idx = routing.Start(courier_idx)
            self._set_constraint_on_var(
                node_idx,
                TimeWindowConstraint(node=node_idx,
                                     is_hard=True,
                                     from_time=start_utilization,
                                     to_time=start_utilization),
                capacity_dimension)
示例#3
0
文件: cvrp.py 项目: anhpngt/chariots
    def from_cvrp_solution(cls, data_model: DataModel,
                           manager: pywrapcp.RoutingIndexManager,
                           routing: pywrapcp.RoutingModel,
                           assignment) -> 'Optional[List[VehicleRoute]]':
        if not assignment:
            return None

        res = []  # type: List[VehicleRoute]
        for vehicle_id in range(data_model.vehicle_number):
            index = routing.Start(vehicle_id)
            route_indices = []  # type: List[int]
            route_distance = 0  # float
            route_load = 0  # float

            while not routing.IsEnd(index):
                node_index = manager.IndexToNode(index)
                route_indices.append(node_index)
                route_load += data_model.demands[node_index]

                previous_index = index
                index = assignment.Value(routing.NextVar(index))
                route_distance += routing.GetArcCostForVehicle(
                    previous_index, index, vehicle_id)

            route_indices.append(0)  # returns to depot
            res.append(
                cls(data_model, vehicle_id, route_indices, route_distance,
                    route_load))

        current_app.logger.debug('CVRP Solution:\n{res}')
        return res
示例#4
0
def draw_route_graph(
    data: dict,
    routing: RoutingModel,
    manager: RoutingIndexManager,
    assignment: Assignment,
    filename: str = 'route.png',
    prog='sfdp',
) -> None:
    """
    Draw a route graph based on the solution of the problem.
    """

    weights = data['weights']
    demands = data['demands']
    time_windows = data['time_windows']
    graph = pgv.AGraph(directed=True)

    def _node(index: int) -> str:
        if index == 0:
            return f'{index}\nDepot'
        return f'{index}\nDemand: {demands[index]}\nRange: {time_windows[index]}'

    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        while not routing.IsEnd(index):
            node_index = manager.IndexToNode(index)
            next_index = assignment.Value(routing.NextVar(index))
            next_node_index = manager.IndexToNode(next_index)
            weight = weights[node_index][next_node_index]
            graph.add_edge(_node(node_index), _node(next_node_index), weight=weight, label=weight)
            index = next_index

    graph.draw(filename, prog=prog)

    print(f'The route graph has been saved to {filename}.')
示例#5
0
def print_solution(
    data: dict,
    routing: RoutingModel,
    manager: RoutingIndexManager,
    assignment: Assignment,
) -> None:
    """
    Print the solution.
    """

    capacity_dimension = routing.GetDimensionOrDie('Capacity')
    time_dimension = routing.GetDimensionOrDie('Time')
    total_time = 0

    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        node_props = []

        while not routing.IsEnd(index):
            props = node_properties(manager, assignment, capacity_dimension, time_dimension, index)
            node_props.append(props)
            index = assignment.Value(routing.NextVar(index))

        props = node_properties(manager, assignment, capacity_dimension, time_dimension, index)
        node_props.append(props)
        route_time = assignment.Value(time_dimension.CumulVar(index))
        route = "\n  -> ".join(['[Node %2s: Load(%s) Time(%2s, %s)]' % prop for prop in node_props])
        plan_output = (f'Route for vehicle {vehicle_id}:\n  {route}\n'
                       f'Load of the route: {props[1]}\nTime of the route: {route_time} min\n')
        print(plan_output)

        total_time += route_time

    print(f'Total time of all routes: {total_time} min')
示例#6
0
    def _set_arc_distance(self, data: VehicleRoutingProblemInstance,
                          manager: RoutingIndexManager, routing: RoutingModel):
        # ========= DISTANCE CONSTRAIN =========
        cost_callback_indices = []
        # model "cost between nodes per vehicle"
        for vehicle_idx in range(data.num_plans_to_create):

            def vehicle_cost_callback(from_index, to_index):
                from_node = manager.IndexToNode(from_index)
                to_node = manager.IndexToNode(to_index)
                distance = data.car_distance_matrix[from_node][
                    to_node]  # in meters

                return distance

            cost_callback_index = routing.RegisterTransitCallback(
                vehicle_cost_callback)
            cost_callback_indices.append(cost_callback_index)
            routing.SetArcCostEvaluatorOfVehicle(cost_callback_index,
                                                 vehicle_idx)

        routing.AddDimensionWithVehicleTransits(
            cost_callback_indices,
            0,  # waiting time
            MAX_TIMESTAMP_VALUE,  # maximum distance per vehicle
            True,  # Force start cumul to zero.
            self.DISTANCE_DIMENSION_NAME)
示例#7
0
    def solve(self, indices_to_visit: List[int] = None) -> Dict[str, Any]:
        """Finds the optimal order of facilities to minimize distance.

        Parameters
        ----------
        indices_to_visit : List[int]
            The list of indices corresponding to the desired facilities to visit

        Returns
        -------
        Dict[str, Any]
            Soltution dictionary with keys:
            - 'objective', set to objective value (minified distance)
            - 'order', instructions for the order of facilities to visit
        """
        if indices_to_visit is None:
            indices_to_visit = list(range(len(self.matrix)))

        # make sure home location is in the listed, and that the list is sorted
        if self.home_index not in indices_to_visit:
            indices_to_visit.append(self.home_index)
        indices_to_visit.sort()

        data = self._create_data_model(indices_to_visit)

        # create routing index manager
        manager = RoutingIndexManager(len(data['distance_matrix']),
                                      data['num_vehicles'], data['home'])

        # create routing model
        routing = RoutingModel(manager)

        def distance_callback(from_index, to_index):
            # returns distance between two nodes
            from_node = manager.IndexToNode(from_index)
            to_node = manager.IndexToNode(to_index)
            dist = data['distance_matrix'][from_node][to_node]

            return dist

        transit_callback_index = routing.RegisterTransitCallback(
            distance_callback)

        # define cost of each arc
        routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

        # set first solution heuristic
        search_params = pywrapcp.DefaultRoutingSearchParameters()
        search_params.first_solution_strategy = (
            routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

        # solve problem
        assignment = routing.SolveWithParameters(search_params)

        return self._extract_solution(manager, routing, assignment,
                                      indices_to_visit)
示例#8
0
def print_solution(
	data: dict,
	routing: RoutingModel,
	manager: RoutingIndexManager,
	assignment: Assignment,
) -> None:
	capacity_dimension = routing.GetDimensionOrDie('Capacity')
	time_dimension = None
	total_cost = 0
	if 'time_windows' in data.keys():
		time_dimension = routing.GetDimensionOrDie('Time')
		total_time = 0

	for vehicle_id in range(data['num_vehicles']):
		index = routing.Start(vehicle_id)
		node_props = []

		while not routing.IsEnd(index):
			props = node_properties(data, manager, assignment, capacity_dimension, time_dimension, index)
			node_props.append(props)
			index = assignment.Value(routing.NextVar(index))

		props = node_properties(data, manager, assignment, capacity_dimension, time_dimension, index)
		node_props.append(props)

		# arc weight
		cost = 0 
		node_indexes = [prop[0] for prop in node_props]
		for i in range(len(node_indexes)-1):
			idx_from = node_indexes[i]
			idx_to = node_indexes[i+1]
			cost += data['dist_mat'][idx_from][idx_to]
		total_cost += cost

		if 'time_windows' in data.keys():
			route_time = assignment.Value(time_dimension.CumulVar(index))
			route = "\n  -> ".join(['[Node %2s(%s)TW(%2s, %2s): Vehicle Load(%2s) and Arrived(%2s)]' % prop for prop in node_props])
			plan_output = (f'Route for vehicle {vehicle_id}:\n     {route}\n'
						   f'Cost: {cost}\nLoad: {props[-1]}\nTime: {route_time} min\n')
			print(plan_output)

			total_time += route_time
		else:
			route = "\n  -> ".join(['[Node %2s(%s): Vehicle Load(%2s)]' % prop for prop in node_props])
			plan_output = (f'Route for vehicle {vehicle_id}:\n     {route}\n'
						   f'Cost: {cost}\nLoad: {props[-1]}\n')
			print(plan_output)

	print(f'Total cost of all routes: {total_cost}\n')
	return total_cost
	if 'time_windows' in data.keys():
		print('*** format ***: \n[Node node_index(demand)TW(Time Window min, max): Vehicle Load(accumulated load) and Arrived(time)]')
		print(f'Total time of all routes: {total_time} min')
示例#9
0
    def _solve(self, routing: RoutingModel,
               search_parameters: RoutingSearchParameters,
               initial_routes) -> Assignment:

        if initial_routes is None:
            solution = routing.SolveWithParameters(search_parameters)
        else:
            routing.CloseModelWithParameters(search_parameters)
            initial_solution = routing.ReadAssignmentFromRoutes(
                initial_routes, True)
            solution = routing.SolveFromAssignmentWithParameters(
                initial_solution, search_parameters)

        return solution
示例#10
0
def add_capacity_constraints(routing: pywrapcp.RoutingModel, data: dict,
                             demand_callback):
    """
    Add capacity constraints.
    """
    demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
    routing.AddDimensionWithVehicleCapacity(
        demand_callback_index,
        slack_max=0,  # null slack
        # vehicle maximum capacities
        vehicle_capacities=data['vehicle_capacities'],
        fix_start_cumul_to_zero=True,  # start cumul to zero
        name='Capacity',
    )
示例#11
0
    def apply(self, solver: RoutingModel):
        """Vehicle's occupation is restricted based on demand"""

        callback_index = solver.RegisterUnaryTransitCallback(self._callback)
        solver.AddDimensionWithVehicleCapacity(
            evaluator_index=callback_index,
            slack_max=0,
            vehicle_capacities=[
                vehicle.capacity
                for vehicle in self.problem.vehicles.values()
            ],
            fix_start_cumul_to_zero=True,
            name='capacity_constraint'
        )
    def apply(self, manager:  pywrapcp.RoutingModel, routing: pywrapcp.RoutingModel, data_model: DataModel):
        def distance_callback(from_index, to_index):
            """Returns the distance between the two nodes."""
            # Convert from routing variable Index to distance matrix NodeIndex.
            from_node = manager.IndexToNode(from_index)
            to_node = manager.IndexToNode(to_index)
            return data_model.distance_matrix[from_node][to_node]

        transit_callback_index = routing.RegisterTransitCallback(distance_callback)
        routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

        dimension_name = 'Distance'
        routing.AddDimension(
            transit_callback_index,
            0,  # no slack
            3000,  # vehicle maximum travel distance
            True,  # start cumul to zero
            dimension_name)
        distance_dimension = routing.GetDimensionOrDie(dimension_name)
        distance_dimension.SetGlobalSpanCostCoefficient(100)

        for i in range(data_model.number_of_engineers):
            routing.AddVariableMinimizedByFinalizer(
                distance_dimension.CumulVar(routing.Start(i)))
            routing.AddVariableMinimizedByFinalizer(
                distance_dimension.CumulVar(routing.End(i)))

        return routing
示例#13
0
def print_solution(data: dict, routing: pywrapcp.RoutingModel,
                   assignment: pywrapcp.Assignment):
    """
	Print routes on console.
	"""
    capacity_dimension = routing.GetDimensionOrDie('Capacity')
    time_dimension = routing.GetDimensionOrDie('Time')
    total_time = 0
    d = {}
    r = []

    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        node_props = []

        while not routing.IsEnd(index):
            props = node_properties(routing, assignment, capacity_dimension,
                                    time_dimension, index)
            node_props.append(props)
            index = assignment.Value(routing.NextVar(index))

        props = node_properties(routing, assignment, capacity_dimension,
                                time_dimension, index)
        node_props.append(props)
        route_time = assignment.Value(time_dimension.CumulVar(index))
        route = "\n  -> ".join(['[Node %2s: Load(%s) Time(%2s, %s)]' % prop \
              for prop in node_props])
        plan_output = f'Route for vehicle {vehicle_id}:\n  {route}\n' + \
         f'Load of the route: {props[1]}\nTime of the route: {route_time} min\n'

        # print(plan_output)

        #convert to dict
        ddd = []
        for node in node_props:
            dd = {"node": node[0], "load": node[1], "time": [node[2], node[3]]}
            ddd.append(dd)
        r.append({
            "vehicle_id": vehicle_id,
            "route": ddd,
            "total_time": route_time,
            "load": len(ddd) - 2
        })

        total_time += route_time
    d['solver'] = r
    d['total_time'] = total_time
    # print(f'Total time of all routes: {total_time} min')
    return d
示例#14
0
    def apply(self, manager: pywrapcp.RoutingIndexManager,
              routing: pywrapcp.RoutingModel, data_model: DataModel):
        nodes = data_model.nodes
        engineers = data_model.engineers_to_plan

        for index in range(0, data_model.number_of_nodes):
            if index < data_model.number_of_engineers:
                routing.SetAllowedVehiclesForIndex([index], index)
            else:
                allowed_vehicles = [
                    ind for ind, node in enumerate(engineers)
                    if self.can_visit(data_model, nodes[index], engineers[ind])
                ]
                routing.SetAllowedVehiclesForIndex(allowed_vehicles, index)

        return routing
示例#15
0
    def _set_objective_function(problem: Problem, manager: RoutingIndexManager,
                                solver: RoutingModel):
        """Method to set the objective function of the Optimization Model"""
        def _time_callback(from_index: int, to_index: int):
            """Callback to obtain the complete time between Stops"""

            origin = manager.IndexToNode(from_index)
            destination = manager.IndexToNode(to_index)
            travelling_time = problem.estimations[(origin, destination)]
            service_time = problem.stops[destination].service_time

            return travelling_time + service_time

        callback_index = solver.RegisterTransitCallback(_time_callback)
        solver.SetArcCostEvaluatorOfAllVehicles(callback_index)
        logging.info('Set the objective function to the OptimizationModel.')
示例#16
0
    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 apply(self, manager: pywrapcp.RoutingModel,
              routing: pywrapcp.RoutingModel, data_model: DataModel):
        def demand_callback(from_index):
            """Returns the demand of the node."""
            # Convert from routing variable Index to demands NodeIndex.
            from_node = manager.IndexToNode(from_index)
            return data_model.demands[from_node]

        demand_callback_index = routing.RegisterUnaryTransitCallback(
            demand_callback)
        routing.AddDimensionWithVehicleCapacity(
            demand_callback_index,
            0,  # null capacity slack
            data_model.vehicle_capacities,
            True,  # start cumul to zero
            'Capacity')

        return routing
示例#18
0
    def _set_balance_constraints_on_distance_driven(
            self, data: VehicleRoutingProblemInstance, routing: RoutingModel,
            deliveries: List[Delivery]):
        # ========= BALANCE DISTRIBUTION CONSTRAIN =========
        # https://activimetrics.com/blog/ortools/counting_dimension/
        # A “fair” distribution of loads
        average_load = int(
            2 * len(deliveries) //
            data.num_plans_to_create)  # each delivery has 2 locations
        count_dimension = routing.GetDimensionOrDie(
            self.DISTANCE_DIMENSION_NAME)
        for veh in range(0, data.num_plans_to_create):
            index_end = routing.End(veh)

            # https://github.com/google/or-tools/blob/v8.0/ortools/constraint_solver/routing.h#L2460
            # 5 min penalty for every order over average load
            count_dimension.SetCumulVarSoftLowerBound(index_end, average_load,
                                                      5 * 60)
示例#19
0
def main() -> None:
    """
    Entry point of the program.
    """

    # Parse command line arguments
    args = parse_args()

    # Instantiate the data problem
    data = load_data_model(args.path)

    # Create the Routing Index Manager and Routing Model
    manager = RoutingIndexManager(data["num_locations"], data["num_vehicles"],
                                  data["depot"])
    routing = RoutingModel(manager)

    # Define weights of edges
    weight_callback_index = routing.RegisterTransitCallback(
        create_weight_callback(manager, data))
    routing.SetArcCostEvaluatorOfAllVehicles(weight_callback_index)

    # Add capacity constraints
    demand_callback = create_demand_callback(manager, data)
    demand_callback_index = routing.RegisterUnaryTransitCallback(
        demand_callback)
    add_capacity_constraints(routing, manager, data, demand_callback_index)

    # Add time window constraints
    time_callback_index = routing.RegisterTransitCallback(
        create_time_callback(manager, data))
    add_time_window_constraints(routing, manager, data, time_callback_index)

    # Set first solution heuristic (cheapest addition)
    search_params = DefaultRoutingSearchParameters()
    search_params.first_solution_strategy = FirstSolutionStrategy.PATH_CHEAPEST_ARC
    if args.gls:
        search_params.local_search_metaheuristic = (
            LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
        # NOTE: Since Guided Local Search could take a very long time, we set a
        # reasonable time limit
        search_params.time_limit.seconds = 30
    if args.verbose:
        search_params.log_search = True

    # Solve the problem
    assignment = routing.SolveWithParameters(search_params)
    if not assignment:
        print("No solution found.")
        return

    # Print the solution
    print_solution(data, routing, manager, assignment)

    # Export network and route graphs
    if args.export_network_graph:
        draw_network_graph(args.export_network_graph, data)
    if args.export_route_graph:
        draw_route_graph(args.export_route_graph, data, routing, manager,
                         assignment)
示例#20
0
    def _extract_solution(self, assignment: Assignment, vrp_instance: VehicleRoutingProblemInstance,
                          manager: RoutingIndexManager, routing: RoutingModel) \
            -> VehicleRoutingProblemSolution:
        routes = []
        etas = []
        etds = []

        time_dimension = routing.GetDimensionOrDie(
            self.DURATION_DIMENSION_NAME)
        for vehicle_id in range(vrp_instance.num_plans_to_create):
            index = routing.Start(vehicle_id)

            route = []
            route_etas = []
            route_etds = []

            while not routing.IsEnd(index):
                node = manager.IndexToNode(index)

                if node in vrp_instance.pickup_nodes:
                    this_event_time = vrp_instance.pickup_service_time
                elif node in vrp_instance.drop_nodes:
                    this_event_time = vrp_instance.drop_service_time
                else:
                    this_event_time = 0

                time_var = time_dimension.CumulVar(index)
                eta = assignment.Min(time_var)
                etd = assignment.Max(time_var) + this_event_time

                route.append(node)
                route_etas.append(eta)
                route_etds.append(etd)

                index = assignment.Value(routing.NextVar(index))

            routes.append(route)
            etas.append(route_etas)
            etds.append(route_etds)

        ret = VehicleRoutingProblemSolution(plans=routes, etas=etas, etds=etds)
        return ret
示例#21
0
    def _set_balance_constraints_on_number_of_packages(
            self, data: VehicleRoutingProblemInstance, routing: RoutingModel):
        # ========= BALANCE DISTRIBUTION CONSTRAIN =========
        routing.AddConstantDimension(
            1,  # increment by one every time
            100000,  # max value forces equivalent # of jobs
            True,  # set count to zero
            self.COUNT_DIMENSION_NAME)

        average_load = int(
            2 * len(data.drop_nodes) //
            data.num_plans_to_create)  # each delivery has 2 locations
        count_dimension = routing.GetDimensionOrDie(self.COUNT_DIMENSION_NAME)
        for veh in range(0, data.num_plans_to_create):
            index_end = routing.End(veh)

            # https://github.com/google/or-tools/blob/v8.0/ortools/constraint_solver/routing.h#L2460
            # 5 min penalty for every order over average load
            count_dimension.SetCumulVarSoftUpperBound(index_end,
                                                      average_load + 6, 5 * 60)
示例#22
0
def add_time_window_constraints(routing: pywrapcp.RoutingModel, data: dict,
                                time_callback):
    """
    Add time window constraints.
    """
    time = 'Time'
    horizon = 120
    routing.AddDimension(
        evaluator=time_callback,
        slack_max=horizon,  # allow waiting time
        capacity=horizon,  # maximum time per vehicle
        # Don't force start cumul to zero. This doesn't have any effect in this example,
        # since the depot has a start window of (0, 0).
        fix_start_cumul_to_zero=False,
        name=time,
    )
    time_dimension = routing.GetDimensionOrDie(time)
    for loc_node, (open_time, close_time) in enumerate(data['time_windows']):
        index = routing.NodeToIndex(loc_node)
        time_dimension.CumulVar(index).SetRange(open_time, close_time)
示例#23
0
    def _set_pickup_delivery_constraints(self,
                                         data: VehicleRoutingProblemInstance,
                                         routing: RoutingModel,
                                         manager: RoutingIndexManager):
        time_dimension = routing.GetDimensionOrDie(
            self.DURATION_DIMENSION_NAME)

        # ========= PICKUP/DELIVERY CONSTRAIN =========
        # Define Transportation Requests.
        solver: Solver = routing.solver()
        for pickup_node, delivery_node in data.deliveries_not_started:
            pickup_index = manager.NodeToIndex(pickup_node)
            delivery_index = manager.NodeToIndex(delivery_node)
            routing.AddPickupAndDelivery(pickup_index, delivery_index)
            solver.Add(
                routing.VehicleVar(pickup_index) == routing.VehicleVar(
                    delivery_index))
            solver.Add(
                time_dimension.CumulVar(pickup_index) <=
                time_dimension.CumulVar(delivery_index))

        # Define constraint of deliveries in progress - only vehicle that picked the order is able to finish it
        for courier_idx, node in data.deliveries_in_progress:
            index = manager.NodeToIndex(node)
            routing.SetAllowedVehiclesForIndex([courier_idx], index)
示例#24
0
def add_capacity_constraints(routing: pywrapcp.RoutingModel, data: dict,
                             demand_callback):
    """
    Add capacity constraints.
    """
    routing.AddDimensionWithVehicleCapacity(
        evaluator=demand_callback,
        slack_max=0,  # null slack
        # vehicle maximum capacities
        vehicle_capacities=data['vehicle_capacities'],
        fix_start_cumul_to_zero=True,  # start cumul to zero
        name='Capacity',
    )
示例#25
0
def add_time_window_constraints(
    routing: RoutingModel,
    manager: RoutingIndexManager,
    data: dict,
    time_callback_index: int,
) -> None:
    max_ = 120
    routing.AddDimension(
        time_callback_index,
        slack_max=
        max_,  # An upper bound for slack (the wait times at the locations)
        capacity=
        max_,  # An upper bound for the total time over each vehicle's route
        # Don't force start cumul to zero. This doesn't have any effect in this example,
        # since the depot has a start window of (0, 0).
        fix_start_cumul_to_zero=False,
        name='Time',
    )
    time_dimension = routing.GetDimensionOrDie('Time')
    for loc_idx, (open_time, close_time) in enumerate(data['time_windows']):
        index = manager.NodeToIndex(loc_idx)
        time_dimension.CumulVar(index).SetRange(open_time, close_time)
示例#26
0
    def _set_arc_durations(self, data: VehicleRoutingProblemInstance,
                           manager: RoutingIndexManager, routing: RoutingModel,
                           dimension_name: str):
        # ========= DURATION CONSTRAIN =========
        cost_callback_indices = []
        # model "cost between nodes per vehicle"
        for vehicle_idx in range(data.num_plans_to_create):

            def vehicle_cost_callback(from_index, to_index):
                from_node = manager.IndexToNode(from_index)
                to_node = manager.IndexToNode(to_index)
                time = data.car_duration_matrix[from_node][
                    to_node]  # in seconds

                is_pickup = from_node in data.pickup_nodes
                is_drop = from_node in data.drop_nodes

                waiting_time = 0
                if is_pickup:
                    waiting_time = ConfigProvider.get_config(
                    ).pickup_waiting_time
                elif is_drop:
                    waiting_time = ConfigProvider.get_config(
                    ).drop_waiting_time

                return time + waiting_time

            cost_callback_index = routing.RegisterTransitCallback(
                vehicle_cost_callback)
            cost_callback_indices.append(cost_callback_index)

        routing.AddDimensionWithVehicleTransits(
            cost_callback_indices,
            MAX_TIMESTAMP_VALUE,  # waiting time
            MAX_TIMESTAMP_VALUE,  # maximum time per vehicle
            # since we are using timestamps as measuring unit we should not overflow
            False,  # Don't force start cumul to zero.
            dimension_name)
示例#27
0
    def _extract_solution(self, manager: RoutingIndexManager,
                          routing: RoutingModel, assignment: Assignment,
                          indices_to_visit: List[int]) -> Dict[str, Any]:
        """Transform results to a usable format

        Parameters
        ----------
        manager : RoutingIndexManager
            OR-tools' object to manage conversion between NodeIndex and variable index
        routing : RoutingModel
            OR-tools' object for route solving
        assignment : Assignment
            OR-tools' object for mapping from variable to domains
        indices_to_visit : List[int]
            The list of indices corresponding to the desired facilities to visit        

        Returns
        -------
        Dict[str, Any]
            With keys:
            - 'objective', set to objective value (minified distance)
            - 'order', instructions for the order of facilities to visit

        """
        sln = {"objective": assignment.ObjectiveValue()}

        stop_indices = []
        index = routing.Start(0)
        while not routing.IsEnd(index):
            relative_index = manager.IndexToNode(index)
            stop_indices.append(indices_to_visit[relative_index])
            previous_index = index
            index = assignment.Value(routing.NextVar(index))
        relative_index = manager.IndexToNode(index)
        stop_indices.append(indices_to_visit[relative_index])
        sln["order"] = stop_indices
        return sln
示例#28
0
    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.')
示例#29
0
def add_time_window_constraints(
    routing: RoutingModel,
    manager: RoutingIndexManager,
    data: dict,
    time_callback_index: int,
) -> None:
    """
    Add time window constraints.
    """

    horizon = 120
    routing.AddDimension(
        time_callback_index,
        slack_max=horizon,  # allow waiting time
        capacity=horizon,  # maximum time per vehicle
        # Don't force start cumul to zero. This doesn't have any effect in this example,
        # since the depot has a start window of (0, 0).
        fix_start_cumul_to_zero=False,
        name='Time',
    )
    time_dimension = routing.GetDimensionOrDie('Time')
    for loc_idx, (open_time, close_time) in enumerate(data['time_windows']):
        index = manager.NodeToIndex(loc_idx)
        time_dimension.CumulVar(index).SetRange(open_time, close_time)
示例#30
0
def node_properties(
    routing: pywrapcp.RoutingModel,
    assignment: pywrapcp.Assignment,
    capacity_dimension: pywrapcp.RoutingDimension,
    time_dimension: pywrapcp.RoutingDimension,
    index: int,
) -> tuple:
    """
    Get a node's properties on the index.
    """
    node_index = routing.IndexToNode(index)
    load = assignment.Value(capacity_dimension.CumulVar(index))
    time_var = time_dimension.CumulVar(index)
    time_min, time_max = assignment.Min(time_var), assignment.Max(time_var)
    return (node_index, load, time_min, time_max)