ECLiPSeで分枝限定法(branch and bound)ライブラリを用いてナップサック問題を解く

ECLiPSe CLPを用いて以下のナップサック問題を解きます。
Example の Knapsack のページ を参考にしてプログラムを作成しました。

問題(Problems and exercises in Operations Research の 18ページ 3.5 Knapsack Branch and Bound ):

投資銀行の総予算は1400万ユーロで、4種類の投資が可能です。次の表は、投資額(Amount)と各投資による純収入(Net revenue)を示しています(単位は百万ユーロ)。投資を行う場合は、各投資を全額行う必要があります。総純収入を最大化する投資方法を答えよ。
OR_excercises_3_5

この問題文だけでは読み取れなかったのですが、解答を見ると4種類の投資は「投資しない/1個口のみ投資する」の2択らしく、同じ投資を2個以上するのは禁止のようです。

解き方:
「制約を満たす」だけではなく「利益を最大化する」「コストを最小化する」解を求める際は分枝限定法(branch_and_bound)ライブラリを使用します。

分枝限定法の厳密な定義やアルゴリズムに関しては他のページや書籍を参考にしてください。
ECLiPSe CLPのbranch and bound ライブラリでは以下の手順でコストを最小化する解を得ます。
1.コスト以外の制約を満たす解を得ます。
2.その時のコストを計算します。計算したコスト=Aとします。
3.新たな制約「コストがA未満であること」を追加して、解を得ます。
4.上記操作を繰り返して解が得られなくなったら、直前に計算したコストが最小コストの解となります。

プログラム:

解説:
6行目でValuesに[投資1,投資2,投資3,投資4]のそれぞれの投資数(0 or 1)の制約を設定しています。Valuesの個々の要素が確保されているのもこの部分ですが、動作に関してfor系の説明をしなくてはなりません。いつか改めて記事書きます。

13行目の述語solve内にある16行目の minimize/2 で分枝限定法を行っていて、繰り返し実行するgoal(この例ではsearch/6)と、コスト計算結果が入る変数(この例ではCost)を指定すると、先ほど解説した1~4の一連の動作を自動で行ってくれます。minimizeではCostを最小化する解を得ます(問題文が利益最大化を目指すものなので15行目でコスト変数への代入時に符号を逆転してます)

16行目のsearch/6の引数のうち、いくつかを説明します。
第三引数(largest): 制約変数のリストのどの変数から値を設定していくかを決める際、「一番大きい数値をドメインに持つ変数」から決定していきます(すべての変数のドメインが0 or 1なのでこのケースでは意味ないです。コピペしてきたので…)
第四引数(indomain_reverse_split) :制約変数に値を設定していくときの順番ですが、「ドメイン内の一番大きいものから降順に」値を設定していきます(このケースでは1を設定して、そのあと0を設定する)
第五引数(complete) :もれなくすべての選択肢を試します(オプションで端折るものがあります)

実行結果:

6行目からのFound a solution with cost ~ の部分で繰り返しコストの条件を厳しくしながらサーチしているのがわかります。
Valuesを見ると2,3,4番目の投資を行うと最大利益42を得られるようです。

上記の問題を「0/1個口の投資」ではなく「0 ~ N個口の投資を行う」という条件に変更した際の解をサーチするプログラムもついでに掲載します。
プログラム:

7行目のところが変更部分ですが、// Amountの「//」はコメントではなくて演算子で、 「Capacity / Amount の整数部分」を計算します。

実行結果:

やはり解は変わり、44が最大利益となり、1番目の投資先に2個、3番目の投資先に1個投資するのが一番利益が高くなるようです。

ついでに、ネットで見かけた複雑そうな30個の荷物の0-1ナップサック問題を解いてみました(プログラムは前半で掲載したもの使いました)
実行結果:

自分のマシン(Intel(R) Core(TM) i5-3340M CPU @ 2.70GHz 2.70 GHz メモリ8GB しょぼめのノートPC)では36msecで解けていました。

Example の Knapsack のページ を見ると、0/1のナップサック問題(上記の0個/1個口の投資しか許されない問題)の場合には別の解き方を行っていたり、EPLEXライブラリを使用した書き方もできることがわかります。また、ナップサック問題は分枝限定法ではなく動的計画法を用いて解くのもメジャーな解き方のようです。

s

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">