オペレーションズ・リサーチ

OR-ToolsでVehicle Routing Problem with Time Windowsを解く

オペレーションズ・リサーチ

[PR]当サイトはアフィリエイト広告を利用しています。

概要

今回もOR-ToolsでVRPの派生問題を解くという話です。

今回は指定した時間にトラックがその地点を通過しなければいけないという制約を扱います。

OR-Toolsのチュートリアルにほとんどの情報は記載されているので詳細はそちらをご覧ください。

ライセンス関係

OR-Toolsのライセンスは次のようになります。

ortools  v9.0.9048
Copyright (c) 2000 The Apache Software Foundation.  All rights
Released under the Apache Software License

http://www.apache.org/licenses/LICENSE-1.1
This product includes software developed by the Apache Software Foundation (http://www.apache.org/). /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. */

今回考える問題

今回考える例は次のようになります。

各地点の上のリストはその地点をその時間内に訪れなければいけないことを表します。

例えば地点1の上には[5,6]と書かれていますが、これは時間5から6の間に地点1に到達しなければいけないことを示しています。

この図で計算します。

プログラム

これを解くプログラムはチュートリアルに載っているため、今回も変更点だけ載せます。

#routeXY
routeXY = [[0,0],[0,-2],[-4,-2],[-2,-1],[-3,1],[-1,2],[-4,2],[4,-2],[3,1],[4,2]]
distance = []
for i in range(len(routeXY)):
    distance.append([])
    for j in range(len(routeXY)):
        distance[i].append(abs(routeXY[i][0]-routeXY[j][0])+abs(routeXY[i][1]-routeXY[j][1]))

これで地点間の距離をリストdistanceに算出します。

ここで注意なのですが、今回はこのdistanceをタイムテーブルとみなします。

つまり今までは地点0と地点2の距離は6だったのですが、これを6の時間を必要とすると解釈します。

OR-Toolsではこのタイムテーブルは必ずしも距離と一致しません。

同じ距離移動しても移動距離は5なのに移動時間は6のときもあるし、7のときもあるという設定が可能です。

今回は簡単に考えて、トラックは常に等速で移動し、信号などの影響を受けず、純粋にある距離進めば同じ時間で目的地に到達すると考えます。

次にチュートリアルとの変更点です。

def create_data_model():
    """Stores the data for the problem."""
    data = {}
    data['time_matrix'] = distance
    data['time_windows'] = [
        (0,3),
        (5,6),
        (10,12),
        (5,7),
        (5,6),
        (9,10),
        (14,15),
        (7,8),
        (12,14),
        (16,17),
    ]
    data['num_vehicles'] = 4
    data['depot'] = 0
    return data

前回はdata[‘distance_matrix’] = distanceでしたが、ここが

data[‘time_matrix’] = distance

となっています。

data[‘time_windows’]

に上の図で示した地点1の上の[5,6]などの情報を記述します。

地点0は[0,3]ですが、これは時間0から3の間にトラックが地点0に存在するのが許されていることを示しています。

配送トラックは4台。

出発点は地点0です。

次がトラックの設定です。

    routing.AddDimension(
        transit_callback_index,
        30,  # allow waiting time
        30,  # maximum time per vehicle
        False,  # Don't force start cumul to zero.
        time)

30, # allow waiting time

はその地点でトラックが待っていられる時間の上限です。

トラックは地点に到達したらすぐに次の目的地へ移動するのではなく、都合の良い時間までその地点で待つことが許されています。

今回は一つの地点で時間30まで待てます。

30, # maximum time per vehicle

はトラック一台が移動にかけられる時間の合計の上限です。

今回は一台で合計時間30だけ移動できます。

出力

Objective: 48

Route for vehicle 0:

0 Time(0,0) -> 7 Time(7,8) -> 8 Time(12,14) -> 9 Time(16,16) -> 0 Time(22,22)

Time of the route: 22min

Route for vehicle 1:

0 Time(0,0) -> 4 Time(5,6) -> 5 Time(9,9) -> 0 Time(12,12)

Time of the route: 12min

Route for vehicle 2:

0 Time(0,0) -> 1 Time(5,5) -> 0 Time(7,7)

Time of the route: 7min

Route for vehicle 3:

0 Time(0,0) -> 3 Time(5,7) -> 2 Time(10,10) -> 6 Time(14,14) -> 0 Time(20,20)

Time of the route: 20min

Total time of all routes: 61min

これを図にすると次のようになります。

もう少し四方に移動するかと思いましたが、vehicle 3が意外に複雑な動きを見せています。

まとめ

今回は時間に関するスケジュールを制約にしたVRPを練習してみました。

時間制約のある色々なルートを回るときにどうすれば効率的な回り方ができるか考えることができますね。