python-3.x 如何在Google OR工具(CVRPTW)中解释VRP问题?/我哪里出错了?

smtd7mpg  于 2023-11-20  发布在  Python
关注(0)|答案(1)|浏览(112)

我对Google OR工具非常陌生。我最近实施了一个解决方案,但我没有得到我想要的结果。

  • 我有一个以分钟为单位的3900 x 3900的时间矩阵
[12,  0, 52, ..., 40, 22, 22],
   [55, 50,  0, ..., 65, 39, 39],
   ...,
   [41, 40, 66, ...,  0, 36, 36],
   [26, 21, 41, ..., 36,  0,  8],
   [26, 21, 41, ..., 36,  8,  0]]

字符串

  • 每辆车都有时间窗,我想要的时间窗是,
  • 对于仓库(480,540)#8 AM至9 AM,其中480和540以分钟为单位
  • 所有其他停止时间窗口为(540,960),即上午9点至下午4点(16:00)
[(480, 540),
    (540, 960),
    (540, 960),
        ...
    (540, 960),
    (540, 960)]
  #1 depot and 3899 parcels

  • 容量限制是不同的车辆可以携带140 - 160个包裹。
  • 车辆数量是上限(3900/140),其中140是我想在一条路线上的点数。对我们来说,这将是28辆车。
  • 我想要一个2分钟的松弛(我的解释是松弛,时间的司机花在每个位置时,他到达那里)
  • 我保持了60秒的限制,如果我们想丢分的话,我也保持了1000秒的处罚。

我目前的方法给我的解决方案,但它不产生所需的输出。它产生的路线,满足能力,但不满足时间;它给650至900分钟的路线(15小时路线)。也有可能得到路线少于12小时,因为我有一个解决版本的数据。
我不知道我哪里出错了,帮助真的很感激.如果你能帮助我在什么时候出错.我约束太多,如果是的,哪一个(我无法弄清楚我修改和测试了许多参数)?我将提供下面的代码,我将提供print_solution输出转储在一个txt文件中,如果你有什么更深入的了解.
Here is the print dump.
我不能附加或粘贴3900 x 3900矩阵,但你可以在虚拟地址上制作一个100 x 100的MRE。准确地说,我在这个区域有随机坐标:https://goo.gl/maps/tGCo5JuADZHb6AyV6

from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import random
import math

def create_data_model(distmat):
    """Stores the data for the problem."""
    data = {}
    data['time_matrix'] = distmat
    n = len(distmat)
    time_wd = [(480,540)]
    for i in range(n-1):
        time_wd.append((540,960))
    data['time_windows'] = time_wd
    
    cap_dem = [0] #DEPOT 0
    for i in range(n-1):
        cap_dem.append(1) # ALL OTHERS 1
        
    data['demands'] = cap_dem
    
    max_pack = 160
    min_pack = 140
    data['num_vehicles'] = math.ceil(n/min_pack)
    data['vehicle_capacities'] = sorted(random.choices(range(min_pack, max_pack+1),k=data['num_vehicles']),reverse=True)
    data['depot'] = 0
    return data

def print_solution(data, manager, routing, solution):
    """Prints solution on console."""
    print(f'Objective: {solution.ObjectiveValue()}')
    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.Min(time_var),
                                                    solution.Max(time_var))
        
        plan_output += 'Time of the route: {}min\n'.format(
            solution.Min(time_var))
        print(plan_output)
        total_time += solution.Min(time_var)
    print('Total time of all routes: {}min'.format(total_time))

def maincvrptw(distmat):
    """Solve the VRP with time windows."""
    # Instantiate the data problem.
    data = create_data_model(distmat)
    # 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]

    transit_callback_index = routing.RegisterTransitCallback(time_callback)

    # Define cost of each arc.
    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
    time_t='Time'
    
    # Add Time Windows constraint.
    routing.AddDimension(
        transit_callback_index,
        2,  # 2 MINS WAIT AT EACH LOCATION
        960,  # DRIVERS MAX ROUTE TIME 
        False,  # Don't force start cumul to zero.
        time_t)
    
    time_dimension = routing.GetDimensionOrDie(time_t)
    
    # Add time window constraints for each location except depot.
    for location_idx, time_window in enumerate(data['time_windows']):
        if location_idx == data['depot']:
            continue
        index = manager.NodeToIndex(location_idx)
        time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
        
        #PENALTY
        routing.AddDisjunction([manager.NodeToIndex(index)], 1000)
        
    # Add time window constraints for each vehicle start node.
    depot_idx = data['depot']
    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        time_dimension.CumulVar(index).SetRange(
            data['time_windows'][depot_idx][0],
            data['time_windows'][depot_idx][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)))
        

    # Add Capacity constraint.
    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['demands'][from_node]
    
    demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
    routing.AddDimensionWithVehicleCapacity(
        demand_callback_index,
        0,  # null capacity slack
        data['vehicle_capacities'],  # vehicle maximum capacities
        False,  # start cumul to zero
        'Capacity')

        
    # Setting first solution heuristic.
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC)
    search_parameters.time_limit.FromSeconds(60)

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

    # Print solution on console.
    if solution:
        print_solution(data, manager, routing, solution)
        print("Done")
    else:
        print("no solution")
    
    return data, manager, routing, solution

data, manager, routing, solution = maincvrptw(distmat)

oymdgrw7

oymdgrw71#

“现实中的兄弟,你觉得你说的时间窗口,你能覆盖多少个地点?别说140个,就算是100个也不可能,因为两个地点之间的时间差应该是差不多的吧?”而且你有2-3分钟的空闲时间。140*2 = 280分钟=将近5个小时会空闲。地点之间的旅行时间平均为10分钟,在你的情况下,这将成为1400分钟,但你的时间窗口只能容纳420分钟。要么你将不得不减少车辆的数量或尝试使用元启发式求解,以获得更好的解决方案。

相关问题