微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Google-OR VRP w/ TW 在位置的最短停留时间

如何解决Google-OR VRP w/ TW 在位置的最短停留时间

我正在使用 google-OR 工具,尝试设置具有时间窗口和要求约束的 VRP。

为此,我希望车辆前往位置 A,在那里停留指定的时间,然后前往下一个位置。我目前的实现非常糟糕,所以我想知道是否有人可以帮助我。

打印解决方案有时会在相隔很长时间的时间内产生,超过最大等待时间; 30 Time(1682,8093) 而最大等待时间只有 3600,或者导致像 28 Time(23118,23118) 这样的时间窗口,其中指定的等待时间为 900此处不计算。

这是我的代码

Vehicles Routing Problem (VRP) with Time Windows.

from __future__ import print_function
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import pandas as pd
import numpy as np
import pickle

# df = pd.read_excel("spaarnwoudecoordinates.xlsx")
# houses_cleaning_times = df['Time'].tolist()
# houses_to_clean = df['Index'].tolist()
# distance_matrix = pickle.load(open("distancematrix_spaarnwoude_foot.p","rb")) # Index 0 is the 
depot,the starting point for all cleaners
# distance_matrix = [[round(j) for j in i] for i in distance_matrix] # distance matrix has to be 
integers
penalty = 10000  # Penalty should probably equal maxtime because than it mirrors the cost of an extra 
cleaner


def create_data_model(houses_to_clean,number_of_cleaners,maximum_time_capacity,maximum_waiting_time,distance_matrix,houses_cleaning_times,time_windows):
"""Stores the data for the problem."""
if number_of_cleaners == 0:
    number_of_cleaners = len(distance_matrix[0])
data = {}
# Filter the distance matrix on houses to be cleaned
rowfilter = np.take(distance_matrix,houses_to_clean,axis=0)
columnfilter = np.take(rowfilter,axis=1)
data['time_matrix'] = columnfilter  # Multiply columnfilter to create walking times. *3 seems 
reasonable
data['num_vehicles'] = number_of_cleaners
data['depot'] = 0
data['demands'] = [round(houses_cleaning_times[i] * 60) for i in houses_to_clean]
data['time_windows'] = time_windows
data['maximum_time_capacity'] = maximum_time_capacity
data['maximum_waiting_time'] = maximum_waiting_time
return data


def findSolution(data,print):
"""Solve the VRP with time windows."""
# Instantiate the data problem.
data = data

# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),data['num_vehicles'],data['depot'])

# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)

# Create and register a transit callback.
def time_callback(from_index,to_index):
    """Returns the travel time between the two nodes."""
    # Convert from routing variable Index to time matrix NodeIndex.
    from_node = manager.IndexToNode(from_index)
    to_node = manager.IndexToNode(to_index)
    # return data['time_matrix'][from_node][to_node]
    traveltime = data['time_matrix'][from_node][to_node]
    cleaningtime = data['demands'][to_node]
    return traveltime + cleaningtime

transit_callback_index = routing.RegisterTransitCallback(time_callback)

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

# Add Time Windows constraint.
time = 'Time'
routing.AddDimension(
    transit_callback_index,data['maximum_waiting_time'],# allow waiting time
    data['maximum_time_capacity'],# maximum time per vehicle  ### THIS ONE SEEMS TO OVERRULE SetSpanUpperBound ---------WORKING DAY 
OF 7 HOURS IN SECONDS
    True,# True: Do force start cumul to zero.
    time)

time_dimension = routing.GetDimensionorDie(time)
# Add time window constraints for each location except depot.
for location_idx,time_window in enumerate(data['time_windows']):
    if location_idx == 0:
        continue
    index = manager.NodetoIndex(location_idx)
    time_dimension.CumulVar(index).SetRange(int(time_window[0]),int(time_window[1]))

# Add time window constraints for each vehicle start node.
for vehicle_id in range(data['num_vehicles']):
    index = routing.Start(vehicle_id)
    time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],data['time_windows'][0][1])

# Instantiate route start and end times to produce feasible times.
for i in range(data['num_vehicles']):
    routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.Start(i)))
    routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.End(i)))

# Set time limit for finding a solution
# search_parameters = pywrapcp.DefaultRoutingSearchParameters()
# search_parameters.time_limit.seconds = 10

# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PATH_CHEApest_ARC
# PATH_CHEApest_ARC   PATH_MOST_CONSTRAINED_ARC   CHRISTOFIDES

# Set penalty for vehicle use to optimize amount of vehicles
routing.SetFixedcostOfAllVehicles(penalty)

# Solve the problem.
solution = routing.solveWithParameters(search_parameters)

# Print solution on console.
if solution:
    if print:
        print_solution(data,manager,routing,solution)
        calculatescore(data,solution,data['maximum_time_capacity'])
    return (data,solution)
else:
    print("No solution found!")
    return None


def getAmountOfCleaners(data,solution):
# Obtain the amount of cleaners in the solution. This can not easily be done by routing.vehicles() 
because this
# method does not include vehicles that go directly from a starting point to their endpoint
# in Google OR Tools' deFinition a vehicle like this is 'unused' see my GitHub issue.
# Therefore we determine used cleaners by load > 0.
cleaners_needed = 0
for cleaner_id in range(data['num_vehicles']):
    load = 0
    index = routing.Start(cleaner_id)
    while not routing.IsEnd(index):
        node_index = manager.IndexToNode(index)
        load += data['demands'][node_index]
        index = solution.Value(routing.Nextvar(index))
    if load > 0:
        cleaners_needed += 1
return cleaners_needed

def print_solution(data,solution):
"""Prints solution on console."""
time_dimension = routing.GetDimensionorDie('Time')
total_time = 0
for vehicle_id in range(data['num_vehicles']):
    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)
        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.Max(time_var))
    plan_output += 'Time of the route: {} sec\n'.format(
        solution.Min(time_var))
    print(plan_output)
    total_time += solution.Min(time_var)

print('Total time of all routes: {} sec'.format(total_time))

def calculatescore(data,maximum_time_capacity):
time_dimension = routing.GetDimensionorDie('Time')
total_score = 0
for cleaner_id in range(data['num_vehicles']):
    index = routing.Start(cleaner_id)

    while not routing.IsEnd(index):  
        time_var = time_dimension.CumulVar(index)
        node_index = manager.IndexToNode(index)
        if node_index != 0:
            if data['time_windows'][node_index][0] <=  solution.Min(time_var) and 
solution.Max(time_var) <= data['time_windows'][node_index][1]:
                total_score += 1
            elif data['time_windows'][node_index][0] >=  solution.Min(time_var):
                total_score += 0.5
            else:
                total_score -= 1
        index = solution.Value(routing.Nextvar(index))
print('total score or the route was: ' + str(total_score))

def get_routes(solution,manager):
"""Get vehicle routes from a solution and store them in an array."""
# Get vehicle routes and store them in a two dimensional array whose
# i,j entry is the jth location visited by vehicle i along its route.
routes = []
for route_nbr in range(routing.vehicles()):
index = routing.Start(route_nbr)
route = [manager.IndexToNode(index)]
while not routing.IsEnd(index):
  index = solution.Value(routing.Nextvar(index))
  route.append(manager.IndexToNode(index))
routes.append(route)
return routes


def get_routes_cleaner(solution,cleaner_id):
data = get_routes(solution,manager)
return data[cleaner_id]

具有以下输入数据:

np.random.seed(0)                                          #use seed to have the same random number 
every time
A = np.random.randint(low=1,high=10,size=(31,31))
np.fill_diagonal(A,0)
distance_matrix = A
houses_to_clean = [i for i in range(31)]  # number of the houses that have to be cleaned
houses_cleaning_times2 = [0] + list(np.random.randint(low=14,high=16,size=30))  # cleaning between 
14 and 16min

a = [0] + list(np.random.randint(low=27,high=28,size=30) * 15 * 60)
b = [0] + list(np.random.randint(low=0,high=14,size=30) * 15 * 60)
time_windows = list(zip(b,a))  # array of tuples for the time window

data = create_data_model(houses_to_clean,2,28800,3600,houses_cleaning_times2,time_windows)
(data,solution) = findSolution(data,True) #set to true to print

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。