移動時間と配送計画
サプライ・チェインの諸問題に対しては、地点間の移動時間・距離・費用を算出する必要があることがままある。
Google Mapは高い。無料だとOpenStreetMapのOSRMが定番だが、使いにくい。
調べてみたらopentouteserviceなるものを見つけた。大学発らしい。
軽く使ってみた。地図描画はfoliumを使う。両方ともpipで入る。
import openrouteservice as ors
import folium
client = ors.Client(key="上のサイトで得たAPIキーを入れる")
緯度・経度のリストを与えると、距離行列が計算できる。
coordinates = [[13.384116, 52.533558], [13.428726, 52.519355], [13.41774, 52.498929], [13.374825, 52.496369]]
matrix = client.distance_matrix(
locations=coordinates,
profile='foot-walking',
metrics=['distance', 'duration'],
validate=False,
)
for marker in coordinates:
folium.Marker(location=list(reversed(marker))).add_to(m)
print("Durations in secs: {}\n".format(matrix['durations']))
print("Distances in m: {}".format(matrix['distances']))
結果はこうなる。
Durations in secs: [[0.0, 2788.6, 3757.12, 3706.33], [2788.6, 0.0, 1996.2, 3974.9], [3757.12, 1996.2, 0.0, 2644.32], [3706.33, 3974.9, 2644.32, 0.0]]
Distances in m: [[0.0, 3873.13, 5218.31, 5147.78], [3873.13, 0.0, 2772.56, 5520.79], [5218.31, 2772.56, 0.0, 3672.74], [5147.78, 5520.79, 3672.74, 0.0]]
問題は速度だ。OSRMは高速な実装をしているはずだが、それを利用していれば速いはずだ。
Docker Imageも準備されている。配送計画やネットワーク設計に使えそうだ。
とおもったら,配送計画ソルバーもついているようだ.単純な時間枠と積込み・積み降ろしも入っているようだ.マニュアルが不備でよくわからないが,試してみてらわかるだろう.
m = folium.Map(location=[52.521861, 13.40744], tiles='cartodbpositron', zoom_start=13)
vehicle_locations = [[13.390446, 52.506087], [13.384116, 52.533558]]
job_locations = [[13.428726, 52.519355],
[13.41774, 52.498929],
[13.374825, 52.496369],
[13.378859, 52.509796],
[13.400488, 52.509691],
[13.358517, 52.524264]]
# Assign vehicles to do the jobs
vehicles = []
for idx, coords in enumerate(vehicle_locations):
vehicles.append(ors.optimization.Vehicle(
id=idx,
profile='driving-car',
start=coords,
end=coords,
capacity=[3] # Limit capacity so only 3 jobs can be taken by each vehicle
))
folium.Marker(location=list(reversed(coords)), icon=folium.Icon(icon='truck', prefix='fa')).add_to(m)
# Define jobs to be carried out
jobs=[]
for idx, coords in enumerate(job_locations):
jobs.append(ors.optimization.Job(
id=idx,
location=coords,
amount=[1] # Occupies capacity in vehicle
))
folium.Marker(location=list(reversed(coords)), icon=folium.Icon(icon='archive', prefix='fa', color='green')).add_to(m)
optimized = client.optimization(
jobs=jobs,
vehicles=vehicles,
geometry=True, ## will output the geometry,
)
folium.PolyLine(
locations=[list(reversed(coords)) for coords in ors.convert.decode_polyline(optimized['routes'][0]['geometry'])['coordinates']],
color='red'
).add_to(m)
folium.PolyLine(
locations=[list(reversed(coords)) for coords in ors.convert.decode_polyline(optimized['routes'][1]['geometry'])['coordinates']],
color='orange'
).add_to(m)
m