你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

创建多行程优化服务

​​​本指南介绍如何使用 Azure MapsNVIDIA cuOpt 创建行程优化服务。 此服务可自动执行为多个代理和混合车队构建行程的过程,利用 NVIDIA cuOpt 路由优化引擎来优化涉及多个目的地的路线。​

此过程分两步执行,需要出行时间的成本矩阵,还需要一个求解器来优化问题并生成结果。 成本矩阵表示所讨论的每两组位置之间的出行成本,其中包括出行时间成本和其他出行成本。

显示行程优化工作流的屏幕截图。

本文介绍如何:

  • 在 Azure Marketplace 上开始使用 NVIDIA cuOpt。
  • 使用 Azure Maps 路线矩阵 API 获取出行费用。
  • 如何将问题映射到 cuOpt API 调用。
  • 如何使用 cuOpt 响应。
  • 调用 Azure Maps 路线方向 API 来获取路线。

有关快速入门,请参阅多行程优化代码示例。

先决条件

服务支持

此服务可支持以下功能和约束。

路线优化功能 是否支持? 
卡车和汽车
多个行程
多名司机
多天
混合车队
车辆时间范围
时间限制
优先度
代理休息
提货送货
每辆车的成本
最小和最大车辆数

有关支持的功能的完整列表,请参阅 cuOpt 支持的功能

Azure 市场上的 NVIDIA cuOpt 入门

NVIDIA cuOpt 使用 GPU 加速物流求解器和优化来计算具有各种约束的复杂车辆路线问题。 有关详细信息,请参阅 cuOpt 支持的功能列表

cuOpt 包含在 NVIDIA AI Enterprise 中。 若要开始,请访问 Azure 市场

获取出行费用

要进行行程优化,需要传递给 cuOpt 求解器的一些出行指标的方块矩阵。 这可能包括出行时间或距离成本。 成本矩阵是一个方阵,表示所讨论的每对位置之间行驶的成本。

Azure Maps 路线矩阵 API 会计算从出发地到每个目的地的路线的时间和距离成本。 可以将出发地集和目的地集视为表的列标题和行标题,表中每个单元格都包含从出发地前往该单元格的目的地的成本。

例如,一家餐厅有两名司机,他们需要将食物送到 4 个地点。 要解决此问题,首先调用路线矩阵 API 来获取所有位置之间的行程时间。 本示例假定司机的开始和结束位置是餐厅。 如果开始和结束地点不同于仓库,那它们必须被包含在成本矩阵中。

出发地数量 = 目的地数量 = 1(餐厅也称为仓库)+ 4(送餐)

矩阵大小 = 5 个出发地 x 5 个目的地 = 25

注意

Azure Maps 路线矩阵最多可支持 700 个矩阵单元格,近似于 26x26 的方阵。 你可以使用它来规划 26 个地点的行程(包括取餐地点和送餐地点)。

路线矩阵 POST 请求:

https://atlas.microsoft.com/route/matrix?api-version=2025-01-01&routeType=shortest&subscription-key={Your-Azure-Maps-Subscription-key}
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "MultiPoint",
        "coordinates": [
            [4.85106, 52.36006], //restaurant or depot 
            [4.85056, 52.36187], //delivery location 1 
            [4.85003, 52.36241], //delivery location 2 
            [4.42937, 52.50931], //delivery location 3 
            [4.42940, 52.50843]  //delivery location 4 
        ]
      },
      "properties": {
        "pointType": "origins"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "MultiPoint",
        "coordinates": [
            [4.85106, 52.36006], //restaurant or depot 
            [4.85056, 52.36187], //delivery location 1 
            [4.85003, 52.36241], //delivery location 2 
            [4.42937, 52.50931], //delivery location 3 
            [4.42940, 52.50843]  //delivery location 4 
        ]
      },
      "properties": {
        "pointType": "destinations"
      }
    }
  ]
}

路线矩阵响应返回一个 5x5 多维数组,其中每一行表示出发地,列表示目的地。 使用 travelTimeInSeconds 字段获取每个位置对的时间成本。 在整个解决方案中,时间单位应保持一致。 预处理阶段完成后,订单、取餐地点、车队信息和成本矩阵将通过 API 调用发送并导入到 cuOpt 服务器。

以下 JSON 示例显示了成本矩阵示例的 HTTP 响应正文中返回的内容:

cost_matrix_data = [
    [ 0, 10,  8,  6, 10], 
    [10,  0, 12,  8,  6], 
    [ 8, 16,  0,  8,  4], 
    [ 2,  8,  6,  0,  8], 
    [ 6,  6, 10, 12,  0], 
] 

注意

出发地和目的地相同的成本通常为 0,从位置 A 前往位置 B 的成本不一定等于从位置 B 前往位置 B 的成本。

将问题映射到 cuOpt API 调用

本部分介绍如何为 cuOpt 调用生成请求数据。 有关更多示例,请参阅 cuOpt 最佳做法

  1. 设置成本矩阵
  2. 设置车队数据
  3. 设置任务数据
  4. 设置求解器配置(可选)

设置成本矩阵

分析 Azure Maps 路线矩阵 API 响应,以获取位置之间的行程时间来构造成本矩阵。 在下面的示例中,“0”是表示特定车辆类型的键。

"data": {" cost_matrix_data ": {
    "data": {
    "0": [
        [0, 5, 4, 3, 5],
        [5, 0, 6, 4, 3],
        [4, 8, 0, 4, 2],
        [1, 4, 3, 0, 4],
        [3, 3, 5, 6, 0]
    ]
    }}}

可以选择提供多个成本矩阵,具体取决于车辆类型。 某些车辆行驶速度更快,而另一些车辆在驶过某些区域时可能会产生更多成本。 这可以通过为每种车型使用更多额外的成本矩阵来进行建模。 下一个示例有两个矩阵,“0”表示第一辆车,可以是汽车,“1”表示第二辆车,可以是卡车。 请注意,如果车队的车辆特征类似,只需要指定一次成本矩阵。

"data": {" cost_matrix_data ": {
    "data": {
    "0": [
        [0, 5, 4, 3, 5],
        [5, 0, 6, 4, 3],
        [4, 8, 0, 4, 2],
        [1, 4, 3, 0, 4],
        [3, 3, 5, 6, 0]
    ],
    "1": [
        [0, 4, 2, 3, 3],
        [2, 0, 6, 5, 3],
        [3, 8, 0, 3, 2],
        [1, 5, 3, 0, 4],
        [3, 4, 5, 7, 0]
    ],
    }}}

设置车队数据

车队数据可以描述车队的情况,例如车辆数量、起点/终点位置以及车辆容量,求解器可以使用这些数据来确定哪些车辆可以在约束条件下执行任务。

{
     "fleet_data": {
        "vehicle_locations": [
            [0,1], [0,1]
        ],
        "capacities": [[2,3]],
"vehicle_time_windows": [
        [0, 80],
        [1, 40]
    ],
"vehicle_break_time_windows":[
        [
            [20, 25],
            [20, 25]
        ]
    ],
"vehicle_break_durations": [[1, 1, 1, 1, 1]]
        }
    }
  • 车辆位置:在上面的示例中,车队数据指示两辆车,每辆车有一个数组。 这两辆车的开始位置是 0,结束位置是 1。 在环境成本矩阵描述的情况下,这些车辆位置与成本矩阵中的行(或列)索引相对应。
  • 容量:容量阵列指示车辆容量;第一辆车的容量为 2,第二辆车的容量为 3。 容量可以代表各种内容,例如包装重量、服务技能和每辆车运输的量。 在下一部分中,你将创建一个任务 JSON,该任务 JSON 需要每个任务位置的需求维度,需求维度计数将对应于车队数据中的容量维度数。 ​​​例如,如果一辆卡车正在运送货物,那么容量就是每辆车总共可以承载的重量,而需求就是每个订单的重量。 确保两者使用相同的单位(例如磅或公斤)。​
  • 车辆时窗:时窗指定车辆用来完成任务的操作时间。 这可能是代理的班次开始和结束时间。 原始数据可以包含必须转换为浮点值的通用时间戳 (UTC) 日期/时间格式或字符串格式。 (例如:上午 9:00 - 下午 6:00 转换为凌晨 12:00 开始的分钟数 [24 小时制],则为 [540, 1080])。 提供给 cuOpt 求解器的所有时间/成本单位都应该是相同的。
  • 车辆休息:也可以指定车辆休息时窗和时长。 这可以表示代理的午餐休息时间,或根据需要进行的其他休息。 休息时窗格式与车辆时窗格式相同。 提供给 cuOpt 求解器的所有时间/成本单位都应该是相同的。

设置任务数据

任务定义了必须在约束范围内实现的目标。 在最后一英里送达的情况下,这可能包括送达位置、每个位置的需求数量、送达时窗和每个地点的停留时间。

"task_data": {
        "task_locations": [1, 2, 3, 4], 
        "demand": [[3, 4, 4, 3]], 
        "task_time_windows": [[8, 17], [8, 17], [8, 17], [17, 20]], 
        "service_times": [0, 0, 0, 0]
}
  • 任务位置:在上面的示例中,task_locations 指示地点 1、2、3 和 4 处的送达位置。 这些位置与成本矩阵中的行(或列)索引相对应。
  • 需求:需求数组指示每个位置的需求数量;第一个位置有 3 个需求,第二和第三个位置有 4 个需求,最后一个位置有 3 个需求。 需求维度的计数应该与每辆车的容量维度数相对应。
  • 任务时窗:时窗约束指定了何时应完成任务。 为每个任务分配一个开始和结束时窗,任务必须在此时窗内完成。 原始数据可以包含必须转换为浮点值的通用时间戳 (UTC) 日期/时间格式或字符串格式。 (例如:上午 9:00 - 下午 6:00 转换为凌晨 12:00 开始的分钟数 [24 小时制],则为 [540, 1080])。 提供给 cuOpt 求解器的所有时间/成本单位都应该是相同的。
  • 服务时间:这表示完成任务所需的时长。 service_times 数组指定每个任务位置需要的时长。 提供给 cuOpt 求解器的所有时间/成本单位都应该是相同的。

设置求解器配置(可选)

可以选择性地指定求解器配置来分配查找解决方案的最长时间。 这取决于用例,设置的时间限制越高,返回的结果越好。

        "solver_config": {
         "time_limit": 1
        }

注意

根据问题(例如订单优先级或车辆成本),可能会有其他约束。请参阅 cuOpt 支持的功能。 其他功能的预处理方式与示例中介绍的功能类似。

如何使用 cuOpt 响应

cuOpt 求解器会返回每辆车的优化站点和行程。 分析响应并将每个位置转换为坐标点,然后调用 Azure Maps 路线方向 API 来获取路线。 这些优化的路由显示了每个代理的路线路径和行驶方向。

示例请求数据

{
"requestBody": {
"data": {"cost_matrix_data": {"data": {"1": [[0, 5, 4, 3, 5], [5, 0, 6, 4, 3], [4, 8, 0, 4, 2], [1, 4, 3, 0, 4], [3, 3, 5, 6, 0]]}},
"fleet_data": {
        "vehicle_locations": [[0, 0], [0, 0]], 
        "vehicle_ids": ["Car-A", "Car-B"], 
        "vehicle_types": [1, 1], 
        "capacities": [[75, 75]], 
        "vehicle_time_windows": [[8, 18], [8, 17]], 
        "vehicle_break_time_windows": [[[12, 14], [12, 14]]], 
        "vehicle_break_durations": [[0, 0]]
}, 
"task_data": {
        "task_locations": [1, 2, 3, 4], 
        "demand": [[30, 40, 40, 30]], 
        "task_time_windows": [[8, 17], [8, 17], [8, 17], [17, 15]], 
        "service_times": [0, 0, 0, 0]
},
"solver_config": {
         "time_limit": 1
        }},
    "client_version": ""
    }
}

示例响应

  "reqId": "4bdc2610-d821-48dc-b53f-57698015bb2e",
  "status": "fulfilled",
  "percentComplete": 100,
  "response": {
    "response": {
      "solver_response": {
        "status": 0,
        "num_vehicles": 2,
        "solution_cost": 19.0,
        "vehicle_data": {
          "Car-A": {
            "task_id": [
              "Depot",
              "Break",
              "0",
              "2",
              "Depot"
            ],
            "arrival_stamp": [
              8.0,
              13.0,
              13.0,
              17.0,
              18.0
            ],
            "route": [
              0,
              1,
              1,
              3,
              0
            ],
            "type": [
              "Depot",
              "Break",
              "Delivery",
              "Delivery",
              "Depot"
            ]
          },
          "Car-B": {
            "task_id": [
              "Depot",
              "Break",
              "1",
              "3",
              "Depot"
            ],
            "arrival_stamp": [
              8.0,
              12.0,
              12.0,
              14.0,
              17.0
            ],
            "route": [
              0,
              2,
              2,
              4,
              0
            ],
            "type": [
              "Depot",
              "Break",
              "Delivery",
              "Delivery",
              "Depot"
            ]
          }
        },
        "msg": ""
      }
    }
  }
}

调用 Azure Maps 路线方向 API 来获取路线

将 cuOpt 响应中的位置映射到相应的坐标后,cuOpt 服务可与 Azure Maps 路线方向 API 和 Web SDK 一起使用,以创建一个 Web 应用,用于在地图上显示分配的路线和优化路线。 可以根据分配的站点对单个车辆的路线路径进行颜色编码,并将其显示在 Azure Maps 基本数据上。

显示地图上多行程路线的屏幕截图。

后续步骤