簡體   English   中英

如何使用 or-tools 和 google-distance matrix 創建車輛路線優化問題,同時僅取消終點位置?

[英]How to create a vehicle route optimization problem using or-tools and google-distance matrix while nullifying the end location only?

我正在嘗試為具有接送地點的多司機創建車輛路線問題。 每個司機的起點是他們當前的位置,終點是他們結束的任何地方。

我的算法的輸入是一系列批次/長位置。 最終輸出將是為駕駛員決定的最佳(最短)路線,從他的位置開始並在任何位置結束。 我的實際最終輸出是一條從司機位置開始到司機位置結束的路線。

我的問題是如何在使結束位置無效的同時創建距離矩陣(從結束節點到任何其他節點的距離為零)。

這些是將緯度/經度位置轉換為距離矩陣的函數 >>

def create_data():
  """Creates the data."""
  data = {}
  data['API_key'] = xxxxxxxxxxxxx
  data['addresses'] = ["30.588306869629527%2C31.47918156839698", #driver #12 current loca
                       "30.073040504782547%2C31.345765282277267", #order 13 pickup loc
                       "30.068329781020058%2C31.323759091237868", #order 13 dropoff loc
                       "30.073040504782547%2C31.345765282277267", #order 14 pickup loc
                       "30.062493604295614%2C31.34477108388055", #order 14 dropoff loc
                       "30.073040504782547%2C31.345765282277267", #order 15 pickup loc
                       "30.09912973586751%2C31.315054495649424", #order 15 dropoff loc
                       "30.584087371098757%2C31.50439621285545",  #order 16 pickup loc
                       "30.596311789481327%2C31.488618697512486", #order 16 dropoff loc
                       "30.584087371098757%2C31.50439621285545",  #order 17 pickup loc
                       "30.548610813018943%2C31.834700566824836"] #order 17 dropoff loc
  return data

def create_distance_matrix():
  data = create_data()
  addresses = data["addresses"]
  API_key = data["API_key"]
  # Distance Matrix API only accepts 100 elements per request, so get rows in multiple requests.
  max_elements = 100
  num_addresses = len(addresses)
  # Maximum number of rows that can be computed per request.
  max_rows = max_elements // num_addresses
  # num_addresses = q * max_rows + r (q = 2 and r = 4 in this example).
  q, r = divmod(num_addresses, max_rows)
  dest_addresses = addresses
  distance_matrix = []
  # Send q requests, returning max_rows rows per request.
  for i in range(q):
      origin_addresses = addresses[i * max_rows: (i + 1) * max_rows]
      response = send_request(origin_addresses, dest_addresses, API_key)
      distance_matrix += build_distance_matrix(response)

  # Get the remaining remaining r rows, if necessary.
  if r > 0:
      origin_addresses = addresses[q * max_rows: q * max_rows + r]
      response = send_request(origin_addresses, dest_addresses, API_key)
      distance_matrix += build_distance_matrix(response)
  return distance_matrix #the outut is down below


def send_request(origin_addresses, dest_addresses, API_key):
  """ Build and send request for the given origin and destination addresses."""
  def build_address_str(addresses):
    # Build a pipe-separated string of addresses
    address_str = ''
    for i in range(len(addresses) - 1):
      address_str += addresses[i] + '|'
    address_str += addresses[-1]
    return address_str

  request = 'https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial'
  origin_address_str = build_address_str(origin_addresses)
  dest_address_str = build_address_str(dest_addresses)
  request = str(request) + '&origins=' + str(origin_address_str) + '&destinations=' + str(dest_address_str) + '&key=' + API_key
  jsonResult = urllib.request.urlopen(request).read()
  response = json.loads(jsonResult)
  return response


def build_distance_matrix(response):
  distance_matrix = []
  for row in response['rows']:
    row_list = [row['elements'][j]['distance']['value'] for j in range(len(row['elements']))]
    distance_matrix.append(row_list)
  return distance_matrix

然后距離矩陣看起來像這樣 >>

[[0, 77825, 77826, 77825, 79238, 77825, 74846, 5548, 2112, 5548, 45588], 
[85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[82238, 4300, 0, 4300, 3791, 4300, 7753, 81180, 84267, 81180, 101818], 
[85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[85128, 3702, 6139, 3702, 0, 3702, 12171, 84069, 87157, 84069, 103947], 
[85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[82508, 7453, 7172, 7453, 10358, 7453, 0, 76139, 84537, 76139, 101220], 
[3783, 77535, 77536, 77535, 78948, 77535, 74556, 0, 3560, 0, 40769], 
[2959, 79693, 79694, 79693, 81107, 79693, 76715, 3303, 0, 3303, 42743], 
[3783, 77535, 77536, 77535, 78948, 77535, 74556, 0, 3560, 0, 40769], 
[37626, 89250, 89251, 89250, 90663, 89250, 86271, 35225, 36644, 35225, 0]]

Google OR-tools 中,它提到如果我想擁有任意的開始和結束位置,我應該在距離矩陣中添加一行和一列零。 但對我來說,這會造成一個問題,因為我無法將索引映射回緯度/經度位置。 我在此處的帖子中找到的也是相同的解決方案,但仍然存在相同的問題,因為我使用索引映射回緯度/經度位置。

這是我的確切算法 >> https://developers.google.com/optimization/routing/routing_tasks#setting-start-and-end-locations-for-routes只有開始和結束位置是交付者的當前位置,這是將路線映射回實際位置的額外部分導致將索引映射回緯度/經度位置的問題

"Final Output"
# mapping back to order_id and pickup and delivery location
# routes >> [[0, 9, 10, 1, 5, 3, 4, 2, 6, 7, 8]]
def get_deliverer_route(routes):
  addresses = [{'deliverer_12': '30.588306869629527%2C31.47918156839698'}, 
               {'13_pickup': '30.073040504782547%2C31.345765282277267'}, 
               {'13_dropoff': '30.068329781020058%2C31.323759091237868'}, 
               {'14_pickup': '30.073040504782547%2C31.345765282277267'}, 
               {'14_dropoff': '30.062493604295614%2C31.34477108388055'}, 
               {'15_pickup': '30.073040504782547%2C31.345765282277267'}, 
               {'15_dropoff': '30.09912973586751%2C31.315054495649424'}, 
               {'16_pickup': '30.584087371098757%2C31.50439621285545'}, 
               {'16_dropoff': '30.596311789481327%2C31.488618697512486'}, 
               {'17_pickup': '30.584087371098757%2C31.50439621285545'}, 
               {'17_dropoff': '30.548610813018943%2C31.834700566824836'}]
  route_table = []
  deliverer_request = []
  for idx in range(len(routes)):
    # create delivere location id
    address = addresses[idx]
    for key, value in address.items():
      single_loc = {}
      k = key.split('_')
      single_loc['deliverer_id'] = k[1]
      single_loc['coordinates'] = value.replace('%2C', ',')
      deliverer_request = [single_loc]
      route_table.append(deliverer_request)
    # create orders addresses
    route = routes[idx]
    route.pop(0)
    for n in route:
      order_address = addresses[n]
      for key, value in order_address.items():
        single_loc = {}
        k = key.split("_")
        single_loc["order_id"] = k[0]
        single_loc["coordinates"] = value.replace('%2C', ',')
        single_loc["type"] = k[1]
        route_table[idx].append(single_loc)
  return route_table

顯然,它就像在另一個問題中回答一樣簡單。 創建距離矩陣后,我在每一行的開頭添加了一行零和一個額外的零 > 這將告訴算法索引零處的點與任何其他點之間的距離為 0。然后我設置了終點data["ends"] = 0 所以在我的例子中,距離矩陣看起來像這樣 >>

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 77825, 77826, 77825, 79238, 77825, 74846, 5548, 2112, 5548, 45588], 
[0, 85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[0, 82238, 4300, 0, 4300, 3791, 4300, 7753, 81180, 84267, 81180, 101818], 
[0, 85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[0, 85128, 3702, 6139, 3702, 0, 3702, 12171, 84069, 87157, 84069, 103947], 
[0, 85342, 0, 5147, 0, 2770, 0, 8420, 79286, 87371, 79286, 102144], 
[0, 82508, 7453, 7172, 7453, 10358, 7453, 0, 76139, 84537, 76139, 101220], 
[0, 3783, 77535, 77536, 77535, 78948, 77535, 74556, 0, 3560, 0, 40769], 
[0, 2959, 79693, 79694, 79693, 81107, 79693, 76715, 3303, 0, 3303, 42743], 
[0, 3783, 77535, 77536, 77535, 78948, 77535, 74556, 0, 3560, 0, 40769], 
[0, 37626, 89250, 89251, 89250, 90663, 89250, 86271, 35225, 36644, 35225, 0]]

這樣做的代碼如下>>

def create_distance_matrix(deliverers_location, orders):
  data = create_data(deliverers_location, orders)
  addresses = data["addresses"]
  API_key = data["API_key"]
  # Distance Matrix API only accepts 100 elements per request, so get rows in multiple requests.
  max_elements = 100
  num_addresses = len(addresses)
  # Maximum number of rows that can be computed per request.
  max_rows = max_elements // num_addresses
  # num_addresses = q * max_rows + r (q = 2 and r = 4 in this example).
  q, r = divmod(num_addresses, max_rows)
  dest_addresses = addresses
  distance_matrix = []
  # add the zeros row at the beginning of the matrix >> end node distance 
  end_node = []
  for i in range(len(addresses)+1):
    end_node.append(0)
  distance_matrix.append(end_node)
  # Send q requests, returning max_rows rows per request.
  for i in range(q):
      origin_addresses = addresses[i * max_rows: (i + 1) * max_rows]
      response = send_request(origin_addresses, dest_addresses, API_key)
      distance_matrix += build_distance_matrix(response)

  # Get the remaining remaining r rows, if necessary.
  if r > 0:
      origin_addresses = addresses[q * max_rows: q * max_rows + r]
      response = send_request(origin_addresses, dest_addresses, API_key)
      distance_matrix += build_distance_matrix(response)
  
  # Add a row of zeros and a zero at the start of each row
  dist_matrix = []
  for row in distance_matrix:
    if len(row) == len(addresses)+1: # check if the zero is already added to the beginning of the row
      dist_matrix.append(row)        # just add row to the new list
    elif len(row) == len(addresses): 
      row.insert(0,0)                # insert zero at the beginning and append row
      dist_matrix.append(row)
  distance_matrix = dist_matrix
  return distance_matrix

ps,如果有人需要澄清,請隨時聯系:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM