PCガジェットはいつでも安いAmazonで!

OR-ToolsでVehicle Routing Problem(VRP)を解く

目次

概要

今回はOR-Toolsの練習です。

巡回セールスマン問題のような問題にVehicle Routing Problemというものがあります。

簡単に言うと、複数のトラックを使って配送ルートを回って戻ってくるとき、それぞれのトラックの移動距離が最小になる回り方を求めるという問題です。

巡回セールスマン問題のときは一台のトラックで回りましたが、今回は複数台のトラックで回ります。

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.
*/

今回考える問題

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

ノード0からトラックが出発します。トラックは各ノード(1から9まで)を回ってノード0に戻ってきます。

これを計算するために隣接行列を作成します。次のようなリストとなります。

[[0, 2, 6, 3, 4, 3, 6, 6, 4, 6],

[2, 0, 4, 3, 6, 5, 8, 4, 6, 8],

[6, 4, 0, 3, 4, 7, 4, 8, 10, 12],

[3, 3, 3, 0, 3, 4, 5, 7, 7, 9],

[4, 6, 4, 3, 0, 3, 2, 10, 6, 8],

[3, 5, 7, 4, 3, 0, 3, 9, 5, 5],

[6, 8, 4, 5, 2, 3, 0, 12, 8, 8],

[6, 4, 8, 7, 10, 9, 12, 0, 4, 4],

[4, 6, 10, 7, 6, 5, 8, 4, 0, 2],

[6, 8, 12, 9, 8, 5, 8, 4, 2, 0]]

10行10列のリストです。

例えばリスト[0][1]はノード0とノード1の距離です。

この距離をどうやって計算しているかというと次のようなリストから求めています。

[[0,0],[0,-2],[-4,-2],[-2,-1],[-3,1],[-1,2],[-4,2],[4,-2],[3,1],[4,2]]

リスト[0][0]はノード0のx座標、リスト[0][1]はノード0のy座標です。

基準をノード0にしているのでノード0の座標は(0,0)となります。

ノード1はノード0に対してx方向に0、y方向に-2進んだ位置にあるので(0,-2)という座標になります。

そして最初の隣接行列の[0][1]はノード0とノード1の距離でしたね。

これは|x0-x1|+|y0-y1|で計算しています。直線距離だとまた違うのですが、今回はチュートリアルと同様の方法で距離を求めています。

いちいち手計算すると大変なので、座標だけプログラムに渡してプログラムで距離を求めています。

プログラム

チュートリアルとほとんど同じなので変更点だけ載せます。

まず距離を求める部分。

#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]))
print("distance:")
print(distance)

コード上で

data[‘distance_matrix’] = distance

とします(詳細はチュートリアル参照)。

またパラメーターは

data[‘num_vehicles’] = 4

としました。4台のトラックで回ります。

出力

Objective: 1248

Route for vehicle 0:

0 -> 1 -> 7 -> 0

Distance of the route: 12m

Route for vehicle 1:

0 -> 5 -> 6 -> 4 -> 0

Distance of the route: 12m

Route for vehicle 2:

0 -> 8 -> 9 -> 0

Distance of the route: 12m

Route for vehicle 3:

0 -> 2 -> 3 -> 0

Distance of the route: 12m

Maximum of the route distances: 12m

このようになりました。

正直Objective: 1248の意味はわかりませんでした。

計算したら最大でこの距離のルートが見つかったということかもしれません。

ソルバーの中身がわからないので意味はよくわかりません。

出力を見るとすべてのトラックは12mの移動距離で回っているみたいですね。

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

それぞれのトラックが配送エリアを分担して回っている様子がわかります。

また

distance_dimension.SetGlobalSpanCostCoefficient(100)

を100ではなく小さな値にすると4台の指定で回ってもらうはずなのに答えが2台だけとかの出力になりました。

各トラックに分散させて、それぞれのトラックがまんべんなく回ってほしい時にはここの値は大きい値のほうがよさそうです。

ここでもソルバーの中身がわからないのでこれ以上調べられませんでした。

まとめ

今回はOR-Toolsを使ってVRPを解いてみました。

巡回セールスマン問題は一人とか一台を対象にしていますが、複数台で効率よく回るという問題も解けるんですね。

ソルバーの中身はわかりませんが、効率的な出力が得られているので、手作業で考えるよりは効率的かもしれません。

今回は制約がほとんどない移動距離だけの問題でしたが、他に制約を加えたバージョンもあるらしいので勉強していきたいですね。

目次