【问题标题】:OR-Tools for VRP without constraints wrongly grouped没有约束的 VRP 的 OR-Tools 错误分组
【发布时间】:2021-04-06 05:32:33
【问题描述】:

我正在使用 OR 工具来解决 VRP 问题,没有任何限制。以下是源代码:

def create_data_model():
    """Stores the data for the problem."""
    data = {}
    data['distance_matrix'] = [
        [0, 20079, 2613, 8005, 19277, 12468, 13701],
        [0, 0, 21285, 16012, 32574, 35394, 28806],
        [0, 18233, 0, 5392, 19965, 19650, 13064],
        [0, 15013, 5639, 0, 22883, 22570, 15982],
        [0, 32991, 19256, 21815, 0, 18414, 9112],
        [0, 34348, 16976, 23122, 15678, 0, 14647],
        [0, 27652, 13917, 16476, 8043, 14820, 0]
    ]
    data['time_matrix'] = [
        [0, 1955, 508, 1331, 1474, 1427, 1292],
        [0, 0, 1795, 1608, 2057, 2410, 2036],
        [0, 1485, 0, 823, 1370, 1541, 1100],
        [0, 1402, 924, 0, 1533, 1637, 1263],
        [0, 2308, 1663, 1853, 0, 1766, 1104],
        [0, 2231, 1373, 1660, 1441, 0, 1554],
        [0, 1998, 1353, 1543, 764, 1550, 0]
    ]
    data['num_vehicles'] = 6
    data['depot'] = 0
    return data

def print_solution(data, manager, routing, solution):
    """Prints solution on console."""
    max_route_distance = 0
    for vehicle_id in range(data['num_vehicles']):
        index = routing.Start(vehicle_id)
        plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
        route_distance = 0
        while not routing.IsEnd(index):
            plan_output += ' {} -> '.format(manager.IndexToNode(index))
            previous_index = index
            index = solution.Value(routing.NextVar(index))
            route_distance += routing.GetArcCostForVehicle(
                previous_index, index, vehicle_id)
        plan_output += '{}\n'.format(manager.IndexToNode(index))
        plan_output += 'Distance of the route: {}m\n'.format(route_distance)
        print(plan_output)
        max_route_distance = max(route_distance, max_route_distance)
    print('Maximum of the route distances: {}m'.format(max_route_distance))

def test(request):
    # Instantiate the data problem.
    data = create_data_model()
    # Create the routing index manager.
    manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
                                           data['num_vehicles'], data['depot'])
    # Create Routing Model.
    routing = pywrapcp.RoutingModel(manager)
    
    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['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
        1000000000,  # vehicle maximum travel distance
        True,  # start cumul to zero
        dimension_name)
    distance_dimension = routing.GetDimensionOrDie(dimension_name)
    distance_dimension.SetGlobalSpanCostCoefficient(35394)
    
    # Setting first solution heuristic.
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

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

    # Print solution on console.
    if solution:
        print_solution(data, manager, routing, solution)

    return HttpResponse('')

以上所有内容都是从 google 的示例中复制粘贴的,但以下内容除外:

  1. 我自己的距离矩阵和车辆数量
  2. AddDimension 函数中非常大的车辆最大行驶距离
  3. SetGlobalSpanCostCoefficient(35394)
  4. 我按照 OR-Tools solve traveling salesman (TSP) without returning to the home node 将所有节点到 0 的距离(仓库)设置为 0。

上述代码的结果如下所示:

Route for vehicle 0:
 0 ->  1 -> 0
Distance of the route: 20079m

Route for vehicle 1:
 0 ->  5 -> 0
Distance of the route: 12468m

Route for vehicle 2:
 0 ->  4 -> 0
Distance of the route: 19277m

Route for vehicle 3:
 0 ->  2 ->  3 -> 0
Distance of the route: 8005m

Route for vehicle 4:
 0 ->  6 -> 0
Distance of the route: 13701m

Route for vehicle 5:
 0 -> 0
Distance of the route: 0m

Maximum of the route distances: 20079m

为了验证上述输出,我在谷歌地图中标记了点。编号顺序与距离矩阵的顺序相同。

Coords on map

仓库(起点)在 Watthana,可以在标记 B 附近看到。

显然,从 Watthana 出发,单程最便宜的路线应该是 2-1-3。但 Google OR 将其作为两次行程返回(如车辆 0 和 3 的路线所示)。这也可以通过手动添加距离来验证。

从家到2到1到3的距离=2613+5392+15013=23018m

车辆 0 和 3 的距离 = 20079+8005 = 28084m

我做错了什么?我怎样才能让谷歌不把第 1 点分开?另请注意,理想情况下,E、F、D 点也可以被分组,但它们没有。

提前致谢!

【问题讨论】:

    标签: python-3.x or-tools vehicle-routing


    【解决方案1】:

    从这个问题来看,我认为你想要的是减少所有车辆的累计行驶距离。

        distance_dimension.SetGlobalSpanCostCoefficient(35394)
    

    相反,此代码通过向加权为 35394 的目标函数添加跨度成本来确保每辆车行驶的距离最小化。

    global_span_cost =
    coefficient * (Max(dimension end value) - Min(dimension start value))
    

    在您的情况下,这不是一个非常高的优先级,因此解决方案是注释该行降低系数到一个小的值,如 1 或 2,降低它的唯一重要性。

    阅读更多关于GSpanCoeff

    现在解决方案应该是

    Route for vehicle 0:
     0 ->  2 ->  3 ->  1 -> 0
    Distance of the route: 23018m
    
    Route for vehicle 1:
     0 ->  6 ->  4 -> 0
    Distance of the route: 21744m
    
    Route for vehicle 2:
     0 ->  5 -> 0
    Distance of the route: 12468m
    
    Maximum of the route distances: 23018m
    Sum of the route distances: 57230m
    

    【讨论】:

    • 距离回调函数实际上是一个成本评估函数。您可以根据那里的公式返回成本以获得您想要的结果。
    • 但我的定价层级因累积距离而异。说 10 rs/km 为 0-5 公里。然后 25rs/km 跑 5-10km。这种情况我该怎么办?
    猜你喜欢
    • 2021-10-15
    • 1970-01-01
    • 2018-06-17
    • 2019-06-28
    • 1970-01-01
    • 2015-03-05
    • 2021-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多