pulp for python 以外に python-mip の存在を知った為、メモ
参考url
- https://qiita.com/SaitoTsutomu/items/c7b43c2e02710749d117
- https://magazine.techacademy.jp/magazine/45423
- https://kamekokamekame.net/2021/2021-12-24-article.html
写経結果
#!python3 # -*- coding: utf-8 -*- # cf https://magazine.techacademy.jp/magazine/45423 # pip install mip from mip import Model, xsum, minimize, maximize, BINARY import numpy as np import pandas as pd import sys def main(): problem_1() # 100x + 100y の最大化を求める問題 problem_2_1() # ナップザック問題 problem_2_2() # ナップザック問題 problem_3_1() problem_3_2() # 100x + 100y の最大化を求める問題 # cf https://qiita.com/SaitoTsutomu/items/c7b43c2e02710749d117 def problem_1(): print("## start",sys._getframe().f_code.co_name) m = Model() # 数理モデル # 変数 x = m.add_var("x") y = m.add_var("y") # 目的関数 (objective) m.objective = maximize(100 * x + 100 * y) # 制約条件 (subject to) m += x + 2 * y<=16 # 材料Aの上限 m += 3 * x + y<=18 # 材料Bの上限 m.verbose = 0 # ログの非表示化 m.optimize() # ソルバーの実行 print("x=",x.x, "y=",y.x) # ナップザック問題 # cf https://magazine.techacademy.jp/magazine/45423 def problem_2_1(): print("## start",sys._getframe().f_code.co_name) w = [2, 1, 3, 2, 1, 4] # 重さ v = [3, 2, 6, 1, 3, 8] # 価値 W = 10 # 重さの限度:10kg r = range(len(w)) m = Model() x = [ m.add_var(var_type=BINARY) for i in r ] # 目的関数 (objective) m.objective = maximize(xsum(v[i] * x[i] for i in r)) # 制約条件 (subject to) m += xsum(w[i] * x[i] for i in r) <= W m.verbose = 0 # ログの非表示化 m.optimize() selected = [i for i in r if x[i].x >= 0.99] max_value = sum([v[i] for i in selected]) weights = [w[i] for i in selected] print("max value=",max_value, "wights=",weights ) # ナップザック問題. # 変数生成にadd_var_tensor()を使う場合 # cf https://kamekokamekame.net/2021/2021-12-24-article.html def problem_2_2(): print("## start",sys._getframe().f_code.co_name) w = [2, 1, 3, 2, 1, 4] # 重さ v = [3, 2, 6, 1, 3, 8] # 価値 W = 10 # 重さの限度:10kg r = range(len(w)) m = Model() # 1次元の変数. 内容は有/無の為、type=BINARY x = m.add_var_tensor((len(w),),"x", var_type=BINARY) # 目的関数 (objective) m.objective = maximize(xsum(v[i] * x[i] for i in r)) # 制約条件 (subject to) m += xsum(w[i] * x[i] for i in r) <= W m.verbose = 0 # ログの非表示化 m.optimize() selected = [i for i in r if x[i].x >= 0.99] max_value = sum([v[i] for i in selected]) weights = [w[i] for i in selected] print("max value=",max_value, "wights=",weights ) # cf https://qiita.com/SaitoTsutomu/items/c7b43c2e02710749d117 # - 倉庫群から工場群への輸送量を決めたい → 変数 # - 輸送コストを最小化したい → 目的関数 # - 各倉庫からの搬出は、供給可能量以下 → 制約 # - 各工場への搬入は、需要量以上 → 制約 def problem_3_1(): print("## start",sys._getframe().f_code.co_name) nw = 3 # 倉庫数 nf = 4 # 工場数 rnd = np.random.default_rng(0) # 乱数generator supply = rnd.integers(30,50, nw) # 供給 乱数 demand = rnd.integers(20,40, nf) # 需要 〃 cost = rnd.integers(10,20,(nw,nf))# 輸送費〃 m1 = Model() v1 = m1.add_var_tensor((nw, nf), "v1") expr = xsum(xsum(v) for v in cost * v1) m1.objective = minimize(expr) for i in range(nw): m1 += xsum(v1[i]) <= supply[i] for j in range(nf): m1 += xsum(v1[:, j]) >= demand[j] m1.verbose = 0 m1.optimize() # 変数の値を多次元配列で取得 print( v1.astype(float) ) def problem_3_2(): print("## start",sys._getframe().f_code.co_name) nw = 3 # 倉庫数 nf = 4 # 工場数 rnd = np.random.default_rng(0) # 乱数generator supply = rnd.integers(30,50, nw) # 供給 乱数 demand = rnd.integers(20,40, nf) # 需要 〃 cost = rnd.integers(10,20,(nw,nf))# 輸送費〃 dfw = pd.DataFrame({"倉庫":["W1","W2","W3"], "supply": supply}) dff = pd.DataFrame({"工場":["F1","F2","F3", "F4"],"demand": demand}) df = pd.merge(dfw, dff, "cross").assign( cost=cost.flatten() ) # print( df ) m2 = Model() df["Var"] = m2.add_var_tensor((len(df),), "v2") print( df["Var"] ) m2.objective = minimize(xsum(df.cost * df.Var)) for _, gr in df.groupby('倉庫'): m2 += xsum(gr.Var) <= gr.supply.iloc[0] for _, gr in df.groupby('工場'): m2 += xsum(gr.Var) >= gr.demand.iloc[0] m2.verbose = 0 m2.optimize() # 変数の多次元配列を取得 df["Val"] = df.Var.astype(float) # 更にその中から >0 のものを選択 print( df[df.Val > 0] ) if __name__ == '__main__': main()