Esempio n. 1
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')
Esempio n. 2
0
def main():
    numLocations = 8
    depotIndex = 0
    numVehicles = 3
    vehicleCapacity = 3

    times = [[0, 957.7, 748.5, 570.8, 706.7, 574.2, 893.2, 187],
             [975.1, 0, 436.6, 894.6, 293, 446.4, 760.2, 901.2],
             [814.6, 399.6, 0, 458, 352.5, 231.5, 876.8, 675.8],
             [526.8, 841.3, 441.7, 0, 785.8, 598.5, 1266.5, 457.8],
             [733.3, 328.4, 351.6, 748.7, 0, 231.8, 625, 659.4],
             [713.7, 360.9, 174.3, 577.1, 270.3, 0, 845.2, 639.8],
             [917.6, 919.7, 1000.8, 1357.9, 733.1, 931, 0, 996.4],
             [246.7, 901.6, 626.4, 383.8, 673.9, 540.7, 986.4, 0]]

    def timeCallback(s, t):
        return times[s][t]

    #demands = [0, 0, 1, 1, 3, 0, 0, 1]
    demands = [0, 1, 1, 1, 1, 1, 1, 1]

    def demandsCallback(s, _):
        return demands[s]

    pickupDeliveries = [
        (6, 4), (5, 4)
    ]  #[ ( 6, 4 ), ( 5, 4 ), ( 5, 3 ), ( 1, 2 ), ( 5, 2 ), ( 6, 4 ), ( 5, 7 ) ];
    model = RoutingModel(numLocations, numVehicles, depotIndex)
    model.SetArcCostEvaluatorOfAllVehicles(timeCallback)

    model.AddDimension(timeCallback, 28800, 28800, True, 'Time')
    timeDimension = model.GetDimensionOrDie('Time')
    for i in range(numLocations):
        timeDimension.CumulVar(i).SetRange(0, 28800)

    model.AddDimension(demandsCallback, 0, vehicleCapacity, True, 'Capacity')
    capacityDimension = model.GetDimensionOrDie('Capacity')

    solver = model.solver()

    for pickup, delivery in pickupDeliveries:
        pickupIndex = model.NodeToIndex(pickup)
        deliveryIndex = model.NodeToIndex(delivery)

        solver.AddConstraint(
            model.VehicleVar(pickupIndex) == model.VehicleVar(deliveryIndex))
        solver.AddConstraint(
            timeDimension.CumulVar(pickupIndex) <= timeDimension.CumulVar(
                deliveryIndex))

        model.AddPickupAndDelivery(pickup, delivery)

    assignment = model.Solve()

    if not assignment:
        sys.exit('Error: No Assignment')

    printAssignment(assignment, model)
Esempio n. 3
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')
Esempio n. 4
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
Esempio n. 5
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))
Esempio n. 6
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)
Esempio n. 7
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)
    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
Esempio n. 9
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)
Esempio n. 10
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
Esempio n. 11
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)
Esempio n. 12
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)
Esempio n. 13
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)
Esempio n. 14
0
    def _set_time_dimension_constraints(
            self, routing: RoutingModel, manager: RoutingIndexManager,
            dimension_name: str,
            start_time_windows: List[TimeWindowConstraint],
            node_time_windows: List[TimeWindowConstraint],
            num_plans_to_create: int):

        # ========= TIME WINDOW =========
        time_dimension = routing.GetDimensionOrDie(dimension_name)
        for constraint in start_time_windows:
            index = routing.Start(constraint.node)
            self._set_constraint_on_var(index, constraint, time_dimension)

        for constraint in node_time_windows:
            index = manager.NodeToIndex(constraint.node)
            self._set_constraint_on_var(index, constraint, time_dimension)

        # Instantiate route start and end times to produce feasible times.
        for i in range(num_plans_to_create):
            routing.AddVariableMinimizedByFinalizer(
                time_dimension.CumulVar(routing.Start(i)))
            routing.AddVariableMinimizedByFinalizer(
                time_dimension.CumulVar(routing.End(i)))
Esempio n. 15
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)