Long-running tasks¶
If a tasks takes a long time (i.e. more than 120 seconds), then it is recommended to use the https://routing.oaasis.cc/api/vrp-long API instead.
In this case, the initial response will be a 201 Created status code, and the response body will contain a task_id. You can then use this task_id to poll the status of the task until it is completed.
In [20]:
Copied!
import random
import numpy as np
import os
import requests
# load .env file with API key. Alternatively, set the API key
# as OAASIS_API_KEY="..."
from dotenv import load_dotenv; load_dotenv()
import random
import numpy as np
import os
import requests
# load .env file with API key. Alternatively, set the API key
# as OAASIS_API_KEY="..."
from dotenv import load_dotenv; load_dotenv()
Out[20]:
True
Generate Problem Data¶
In [21]:
Copied!
json_data = {}
num_visits = 10
num_vehicles = 3
TIMELIMIT = 150
json_data = {}
num_visits = 10
num_vehicles = 3
TIMELIMIT = 150
Set Coordinates of depot and visits¶
In [22]:
Copied!
# Depot
depot = {
"name": "depot_1",
"index": 0,
"coordinate": {
"lng": random.uniform(126.734, 127.269), # Longitude range of Seoul
"lat": random.uniform(37.413, 37.715), # Latitude range of Seoul
},
}
json_data["depot"] = depot
# Visits
visits = [
{
"name": f"visit_{visit_idx + 1}",
"index": visit_idx + 1,
"coordinate": {
"lng": random.uniform(126.734, 127.269), # Longitude range of Seoul
"lat": random.uniform(37.413, 37.715), # Latitude range of Seoul
},
"volume": 10,
}
for visit_idx in range(num_visits)
]
json_data["visits"] = visits
# Depot
depot = {
"name": "depot_1",
"index": 0,
"coordinate": {
"lng": random.uniform(126.734, 127.269), # Longitude range of Seoul
"lat": random.uniform(37.413, 37.715), # Latitude range of Seoul
},
}
json_data["depot"] = depot
# Visits
visits = [
{
"name": f"visit_{visit_idx + 1}",
"index": visit_idx + 1,
"coordinate": {
"lng": random.uniform(126.734, 127.269), # Longitude range of Seoul
"lat": random.uniform(37.413, 37.715), # Latitude range of Seoul
},
"volume": 10,
}
for visit_idx in range(num_visits)
]
json_data["visits"] = visits
Set Vehicles¶
In [23]:
Copied!
vehicles = [
{
"name": f"vehicle_{vehicle_idx + 1}",
"volume_capacity": 77,
"vehicle_type": "car",
}
for vehicle_idx in range(num_vehicles)
]
json_data["vehicles"] = vehicles
vehicles = [
{
"name": f"vehicle_{vehicle_idx + 1}",
"volume_capacity": 77,
"vehicle_type": "car",
}
for vehicle_idx in range(num_vehicles)
]
json_data["vehicles"] = vehicles
Set Solver Config¶
In [24]:
Copied!
json_data["option"] = {
"objective_type": "minsum",
"timelimit": TIMELIMIT,
"distance_type": "euclidean"
}
json_data["option"] = {
"objective_type": "minsum",
"timelimit": TIMELIMIT,
"distance_type": "euclidean"
}
Solve the Problem¶
In [25]:
Copied!
OAASIS_API_KEY = os.getenv("OAASIS_API_KEY", None)
assert OAASIS_API_KEY is not None, "Please provide an API key!"
headers = {"X-API-KEY": OAASIS_API_KEY, "Accept": "application/vnd.omelet.v2+json"}
product_url = "https://routing.oaasis.cc/api/vrp-long"
tmp_response = requests.post(product_url, json=json_data, headers=headers)
print(tmp_response.status_code)
print(tmp_response.text)
OAASIS_API_KEY = os.getenv("OAASIS_API_KEY", None)
assert OAASIS_API_KEY is not None, "Please provide an API key!"
headers = {"X-API-KEY": OAASIS_API_KEY, "Accept": "application/vnd.omelet.v2+json"}
product_url = "https://routing.oaasis.cc/api/vrp-long"
tmp_response = requests.post(product_url, json=json_data, headers=headers)
print(tmp_response.status_code)
print(tmp_response.text)
201 {"result_url": "https://routing.oaasis.cc/api/get-vrp-result/91193855a3b545cdb3adb5028894fa75", "job_id": "91193855a3b545cdb3adb5028894fa75"}
In [ ]:
Copied!
response = requests.get(tmp_response.json()["result_url"], headers=headers)
print(response.json())
print(response.status_code)
# wait until status_code is 200
while response.status_code != 200:
import time
time.sleep(1)
response = requests.get(tmp_response.json()["result_url"], headers=headers)
response = requests.get(tmp_response.json()["result_url"], headers=headers)
print(response.json())
print(response.status_code)
# wait until status_code is 200
while response.status_code != 200:
import time
time.sleep(1)
response = requests.get(tmp_response.json()["result_url"], headers=headers)
{'message': 'Optimization not finished yet.'} 404
Out[ ]:
{'routes': [{'vehicle_name': 'vehicle_1', 'route_index': [0, 3, 4, 10, 0], 'route_name': ['depot_1', 'visit_3', 'visit_4', 'visit_10', 'depot_1'], 'route_cost_details': {'objective_cost': 53953, 'distance_cost': 53953, 'duration_cost': 0, 'fixed_cost': 0}}, {'vehicle_name': 'vehicle_2', 'route_index': [], 'route_name': [], 'route_cost_details': {'objective_cost': 0, 'distance_cost': 0, 'duration_cost': 0, 'fixed_cost': 0}}, {'vehicle_name': 'vehicle_3', 'route_index': [0, 5, 7, 9, 1, 6, 8, 2, 0], 'route_name': ['depot_1', 'visit_5', 'visit_7', 'visit_9', 'visit_1', 'visit_6', 'visit_8', 'visit_2', 'depot_1'], 'route_cost_details': {'objective_cost': 115195, 'distance_cost': 115195, 'duration_cost': 0, 'fixed_cost': 0}}], 'unassigned_visit_indices': [], 'unassigned_visit_names': [], 'solution_cost_details': {'total_objective_cost': 169148, 'total_distance_cost': 169148, 'total_duration_cost': 0, 'max_distance_cost': 115195, 'max_duration_cost': 0, 'total_fixed_cost': 0, 'unassigned_penalty_cost': 0}}
Visualize the Solution¶
In [31]:
Copied!
import matplotlib.pyplot as plt
from matplotlib import colormaps
# Note the extra "result" key
resp = response.json()["result"]["routing_engine_result"]
fig, ax = plt.subplots(1, figsize=(4, 4))
coordinates = [[depot["coordinate"]["lat"], depot["coordinate"]["lng"]]]
coordinates.extend([
[visit["coordinate"]["lat"], visit["coordinate"]["lng"]] for visit in visits
])
# Scatter the coordinates of the depot and visits
ax.scatter(coordinates[0][0], coordinates[0][1], color="tab:red", marker="x")
for i in range(1, len(coordinates)):
ax.scatter(coordinates[i][0], coordinates[i][1], color="tab:blue")
# Plot the route
num_routes = len(resp["routes"])
colors = colormaps.get_cmap("tab10")
# colors = cm.get_cmap("tab10", num_routes)
for route_idx, route_obj in enumerate(resp["routes"]):
routes = route_obj["route_index"]
route_color = colors(route_idx)
for step_idx in range(len(routes) - 1):
src_idx = routes[step_idx]
dst_idx = routes[step_idx + 1]
src_x, src_y = coordinates[src_idx]
dst_x, dst_y = coordinates[dst_idx]
ax.annotate(
"",
xy=(dst_x, dst_y),
xytext=(src_x, src_y),
arrowprops=dict(
arrowstyle="-|>",
color=route_color,
lw=1.2,
),
size=15,
annotation_clip=False,
)
# Label and title
ax.set_xlabel('Latitude')
ax.set_ylabel('Longitude')
ax.set_title(f'Cost = {resp["solution_cost_details"]["total_objective_cost"]}')
# Grid
ax.grid(axis='both', color='black', alpha=0.1)
plt.tight_layout()
import matplotlib.pyplot as plt
from matplotlib import colormaps
# Note the extra "result" key
resp = response.json()["result"]["routing_engine_result"]
fig, ax = plt.subplots(1, figsize=(4, 4))
coordinates = [[depot["coordinate"]["lat"], depot["coordinate"]["lng"]]]
coordinates.extend([
[visit["coordinate"]["lat"], visit["coordinate"]["lng"]] for visit in visits
])
# Scatter the coordinates of the depot and visits
ax.scatter(coordinates[0][0], coordinates[0][1], color="tab:red", marker="x")
for i in range(1, len(coordinates)):
ax.scatter(coordinates[i][0], coordinates[i][1], color="tab:blue")
# Plot the route
num_routes = len(resp["routes"])
colors = colormaps.get_cmap("tab10")
# colors = cm.get_cmap("tab10", num_routes)
for route_idx, route_obj in enumerate(resp["routes"]):
routes = route_obj["route_index"]
route_color = colors(route_idx)
for step_idx in range(len(routes) - 1):
src_idx = routes[step_idx]
dst_idx = routes[step_idx + 1]
src_x, src_y = coordinates[src_idx]
dst_x, dst_y = coordinates[dst_idx]
ax.annotate(
"",
xy=(dst_x, dst_y),
xytext=(src_x, src_y),
arrowprops=dict(
arrowstyle="-|>",
color=route_color,
lw=1.2,
),
size=15,
annotation_clip=False,
)
# Label and title
ax.set_xlabel('Latitude')
ax.set_ylabel('Longitude')
ax.set_title(f'Cost = {resp["solution_cost_details"]["total_objective_cost"]}')
# Grid
ax.grid(axis='both', color='black', alpha=0.1)
plt.tight_layout()