はじめに
Pythonのpulpを使用して“決定変数を用いたスイッチ(if構文)”を作成したいと考えております。
ここで、“決定変数を用いたスイッチ(if構文)”というのは、例えば「x(xは0以上の整数)とy(yは0,1のバイナリ変数)を決定変数としたとき、xが1以上の整数であればyは1を出力し、xが0であればyは0を出力する」ようなのを指します。
以下には、簡単な例題を用いて、“決定変数を用いたスイッチ(if構文)”の作成に向けて取り組んでみたこととその結果を記載させていただいております。
簡単な例題は、「入門オペレーションズ・リサーチ」(東海大学出版会)、「第1回:最近学んだ数理最適化の定式化のチップスたち 【ブレインパッドの数理最適化ブログ】」の例題を参考にさせていただき、作成しました。
本稿の大まかな流れとしましては、
①基本的な例題(アイス生産問題)を解きます。
②基本的な例題に、自作の“決定変数を用いスイッチ(if構文)”の機能を果たさない制約を導入する場合の説明をします。
③基本的な例題に、(本稿のテーマである)自作の“決定変数を用いたスイッチ(if構文)”の機能を果たす制約を導入する場合の説明をします。(3パターンございます。)
③を試したのですが現状、“決定変数を用いたスイッチ(if構文)”は作成できておりません。
作成できない原因といたしましても、そもそも不可能なことに挑戦しているのか、またはPython(pulp)初心者である私のプログラムの知識が足りないだけなのかもわかっておりません。
そのため、原因分析及び解決方法を見つけるのに、お力添えいただけますと幸いに存じます。
基本的な問題(アイス生産問題)
引用テキストアイス屋さんが、エスプレッソアイス、ラズベリーアイス、2種類のアイスの生産を計画しています。しかし、材料の牛乳は 8000 cc、作業時間は述べ 360 分という制限があり、好きな分量だけ作れるわけではありません。それぞれのアイスに使う牛乳とかかる手間がこのようになっているとき、儲けを最大にする増産計画はどの様になるでしょうか?
牛乳 | 作業時間 | 儲け | |
---|---|---|---|
エスプレッソアイス | 100cc | 7分 | 50円 |
ラズベリーアイス | 150cc | 5分 | 10円 |
上記の問題設定を定式化しますと以下のように表すことができます。
Pythonでプログラムにすると以下のように表すことができます。
Python
1import pulp 2 3problem = pulp.LpProblem('ice', pulp.LpMaximize) 4 5# 決定変数を定義 6x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 7x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 8 9# 目的関数を設定 10problem += 50*x_e +10*x_r 11 12# 制約を設定 13problem += 100*x_e + 150* x_r <= 8000 14problem += 7*x_e + 5* x_r <= 360 15 16# 最適化 17problem.solve() 18 19# 結果の表示 20print("エスプレッソ",x_e.value(),"個") 21print("ラズベリー",x_r.value(),"個") 22print("儲け",pulp.value(problem.objective),"円")
上記のプログラムを実行した結果は以下の通りです。
Python
1エスプレッソ 51.0 個 2ラズベリー 0.0 個 3儲け 2550.0 円
この結果より、儲けを最大にするにはラズベリーアイスを1つも生産しない方が良いことがわかります。
自作の“決定変数を用いスイッチ(if構文)”の機能を果たさない制約を導入する場合(アイス生産問題)
ここで、新たな制約条件を問題設定に加えます。
(新たに加えた制約条件を太文字にしてあります。)
引用テキストアイス屋さんが、エスプレッソアイス、ラズベリーアイス、2種類のアイスの生産を計画しています。しかし、材料の牛乳は 8000 cc、作業時間は述べ 360 分という制限があり、好きな分量だけ作れるわけではありません。それぞれのアイスに使う牛乳とかかる手間がこのようになっているとき、儲けを最大にする増産計画はどの様になるでしょうか?ただし本日、ラズベリーアイス1個分の量のラズベリー(素材)が消費期限を迎えます。よって、廃棄にならないよう少なくとも1個のラズベリーアイスを生産する必要があります。
牛乳 | 作業時間 | 儲け | |
---|---|---|---|
エスプレッソアイス | 100cc | 7分 | 50円 |
ラズベリーアイス | 150cc | 5分 | 10円 |
上記の問題設定を定式化しますと以下のように表すことができます。
Pythonでプログラムにすると以下のように表すことができます。
Python
1import pulp 2 3problem = pulp.LpProblem('ice', pulp.LpMaximize) 4 5# 決定変数を定義 6x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 7x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 8 9# 目的関数を設定 10problem += 50*x_e +10*x_r 11 12# 制約を設定 13problem += 100*x_e + 150* x_r <= 8000 14problem += 7*x_e + 5* x_r <= 360 15 16###新たに加えた制約 17problem += x_r >= 1 18 19# 最適化 20problem.solve() 21 22# 結果の表示 23print("エスプレッソ",x_e.value(),"個") 24print("ラズベリー",x_r.value(),"個") 25print("儲け",pulp.value(problem.objective),"円")
上記のプログラムを実行した結果は以下の通りです。
儲けを最大にしつつ、消費期限が迫ったラズベリー(ラズベリーアイス1個分の量)を廃棄せずにすみました。
Python
1エスプレッソ 50.0 個 2ラズベリー 2.0 個 3儲け 2520.0 円
Challenge1:自作の“決定変数を用いたスイッチ(if構文)”の機能を果たす制約を導入後(アイス生産問題)
一つ前の章では以下のような制約を元の基本的な問題に加えました。
Python
1#新たに加えた制約 2problem += x_r >= 1
今回の質問のテーマに沿わせるために、この制約を以下のような“決定変数を用いスイッチ(if構文)”の機能を果たす制約に書き換えます。
Challenge1
1problem = pulp.LpProblem('ice', pulp.LpMaximize) 2 3# 決定変数を定義 4x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 5x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 6 7###新たに加えた決定変数 8y_r = pulp.LpVariable('y_r', lowBound=0, cat=pulp.LpBinary) 9 10# 目的関数を設定 11problem += 50*x_e +10*x_r 12 13# 制約を設定 14problem += 100*x_e + 150* x_r <= 8000 15problem += 7*x_e + 5* x_r <= 360 16 17###新たに加えた制約 18if x_r.value() >= 1: 19 y_r=1 20 problem += y_r == 1 21 22# 最適化 23problem.solve() 24 25# 結果の表示 26print("エスプレッソ",x_e.value(),"個") 27print("ラズベリー",x_r.value(),"個") 28print("儲け",pulp.value(problem.objective),"円") 29
結果は以下の通りでして、エラーが出ました。
Result1
1~省略~ 2 if x_r.value() >= 1: 3TypeError: '>=' not supported between instances of 'NoneType' and 'int'
Challenge2:自作の“決定変数を用いたスイッチ(if構文)”の機能を果たす制約を導入後(アイス生産問題)
Challenge1でエラーが出たのはプログラムでの制約の表現方法が悪いのかと考えました。
そのため、試しに“x_r.value”の“.value”を外してみることにしました。
Challenge2
1import pulp 2 3problem = pulp.LpProblem('ice', pulp.LpMaximize) 4 5# 決定変数を定義 6x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 7x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 8 9###新たに加えた決定変数 10y_r = pulp.LpVariable('y_r', lowBound=0, cat=pulp.LpBinary) 11 12# 目的関数を設定 13problem += 50*x_e +10*x_r 14 15# 制約を設定 16problem += 100*x_e + 150* x_r <= 8000 17problem += 7*x_e + 5* x_r <= 360 18 19###新たに加えた制約 20if x_r >= 1: 21 y_r=1 22 problem += y_r == 1 23 24 25# 最適化 26problem.solve() 27 28# 結果の表示 29print("エスプレッソ",x_e.value(),"個") 30print("ラズベリー",x_r.value(),"個") 31print("儲け",pulp.value(problem.objective),"円") 32
結果は以下の通りでして、エラーは出なかったもののラズベリーアイスが0個であることから導入した制約は制約として認識(反映)されていないことがわかります。
Result2
1エスプレッソ 51.0 個 2ラズベリー 0.0 個 3儲け 2550.0 円
Challenge3:自作の“決定変数を用いたスイッチ(if構文)”の機能を果たす制約を導入後(アイス生産問題)
次に、決定変数y_rを使用するのはいったん諦め、y_rを使用しない(別の決定変数で置き換えない)スイッチ機能のある制約およびプログラムをmax関数を用いて作成してみました。
Challenge3
1import pulp 2 3problem = pulp.LpProblem('ice', pulp.LpMaximize) 4 5# 決定変数を定義 6x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 7x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 8 9# 目的関数を設定 10problem += 50*x_e +10*x_r 11 12# 制約を設定 13problem += 100*x_e + 150* x_r <= 8000 14problem += 7*x_e + 5* x_r <= 360 15 16###新たに加えた制約 17problem += max(x_r,0) >= 1 18 19 20# 最適化 21problem.solve() 22 23# 結果の表示 24print("エスプレッソ",x_e.value(),"個") 25print("ラズベリー",x_r.value(),"個") 26print("儲け",pulp.value(problem.objective),"円") 27
結果は以下の通りでして、エラーが出ました。
このようなmax関数を使用した制約を作成することはできないようです。
Result3
1~省略~ 2 problem += max(x_r,0) >= 1 3TypeError: '>' not supported between instances of 'int' and 'LpVariable'
以上、3つの方法で取り組んでみましたが決定変数を用いてスイッチ(if構文)を作成することができませんでした。
そもそもpulpでこのような制約(=決定変数を用いてスイッチ(if構文))を作成し、解くことは不可能なのでしょうか。
(勉強不足で恐縮なのですが、もしや非線形問題になっていてpulpでは表現できないのでしょうか。)
それとも私のプログラムの書き方が悪いだけなのでしょうか。
よろしければ原因と解決方法をご教授いただけますと幸いに存じます。
(できたら慣れているpulpを使用したいのですが、仮にpulpを使用しなければプログラムを記述することができるのであれば挑戦したいと思いますので、ご教授下さりますと幸いに存じます。)
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。