如何解决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 举报,一经查实,本站将立刻删除。