無線通信ネットワーク最適化 PuLP

無線通信ネットワーク最適化

無線通信ネットワーク最適化の一例として、ネットワークの帯域幅割り当て問題を考えてみましょう。

この問題では、各ユーザーが必要なデータレートを満たすために最小の帯域幅を割り当てることを目指します。

以下に、この問題を解くためのPythonとPuLPを使用したコードを示します。

この例では、3人のユーザーがいると仮定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from pulp import *
import numpy as np
import matplotlib.pyplot as plt

# ユーザー数
n_users = 3

# ユーザーごとの必要なデータレート (Mbps)
data_rates = np.array([5, 10, 8])

# ユーザーごとの信号対雑音比 (SNR) (dB)
snrs = np.array([10, 20, 15])

# 帯域幅 (Hz)
B = 2000000

# ノイズパワー (W)
N = 10**-13

# 問題の定義
prob = LpProblem("Bandwidth_Allocation", LpMinimize)

# 変数の定義
x = [LpVariable(f"x{i}", lowBound=0) for i in range(n_users)]

# 目的関数
prob += lpSum(x)

# 制約条件
for i in range(n_users):
prob += x[i] * np.log2(1 + snrs[i]) >= data_rates[i]

# 最適化問題を解く
prob.solve()

# 結果を表示
print("最適な帯域幅割り当て: ", [value(xi) for xi in x])

# グラフ化
plt.bar(range(n_users), [value(xi) for xi in x])
plt.xlabel('User')
plt.ylabel('Bandwidth')
plt.show()

このコードは、各ユーザーに必要な最小の帯域幅を割り当てる問題を解きます。

目的関数は、割り当てられた帯域幅の合計を最小化することです。

制約条件は、各ユーザーが必要なデータレートを満たすことを保証します。

最後に、各ユーザーに割り当てられた最適な帯域幅を棒グラフで表示します。

これにより、各ユーザーがどの程度の帯域幅を使用しているかを視覚的に理解することができます。

[実行結果]

解説

この問題は、無線通信ネットワークにおける帯域幅割り当ての問題を解くものです。

各ユーザーは一定のデータレートを必要としており、それを満たすためには一定の帯域幅が必要です。

しかし、全体の帯域幅は限られているため、どのユーザーにどれだけの帯域幅を割り当てるかを最適化する必要があります。


この問題を解くために、線形計画問題を設定します。

目的関数は、割り当てられた帯域幅の合計を最小化することです。

これは、全体の帯域幅を最も効率的に使用するためのものです。


制約条件は、各ユーザーが必要なデータレートを満たすことを保証します。

これは、ユーザーごとの信号対雑音比(SNR)と割り当てられた帯域幅を用いて計算されます。

具体的には、シャノンの定理を用いて、割り当てられた帯域幅とSNRから達成可能なデータレートを計算し、それがユーザーの必要なデータレート以上であることを保証します。


この問題を解くと、各ユーザーに割り当てるべき最適な帯域幅が得られます。

そして、その結果を棒グラフで表示することで、各ユーザーがどの程度の帯域幅を使用しているかを視覚的に理解することができます。

ソフトマージンサポートベクターマシン CVXPY

ソフトマージンサポートベクターマシン

ソフトマージンサポートベクターマシン(SVM)は、データが完全に分離できない場合に使用されます。

以下に、2次元のデータセットに対するソフトマージンSVMの例を示します。

この例では、CVXPYを使用して最適化問題を解き、matplotlibを使用して結果をグラフ化します。


まず、必要なライブラリをインポートします。

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

次に、ランダムな2次元データセットを生成します。

1
2
3
4
5
6
np.random.seed(1)
n = 50
d = 2
X = np.random.randn(n, d)
delta = np.random.uniform(-0.5, 0.5, size=(n,1))
Y = 2*(X[:,0:1] + delta > X[:,1:2]) - 1

次に、ソフトマージンSVMの最適化問題を定義します。

1
2
3
4
5
6
7
8
9
w = cp.Variable((d, 1))
b = cp.Variable()
xi = cp.Variable((n, 1))
C = 1.0

objective = cp.Minimize(cp.norm(w, 2) + C*cp.sum(xi))
constraints = [cp.multiply(Y, X @ w + b) >= 1 - xi, xi >= 0]
prob = cp.Problem(objective, constraints)
prob.solve()

最後に、結果をグラフ化します。

1
2
3
4
5
6
7
8
9
10
plt.figure(figsize=(8,8))
plt.scatter(X[:,0], X[:,1], c=Y.flatten())
slope = -w.value[0] / w.value[1]
intercept = -b.value / w.value[1]
x_vals = np.linspace(-2, 2, 100)
plt.plot(x_vals, slope * x_vals + intercept, 'k-')
plt.fill_between(x_vals, slope * x_vals + intercept - 1 / np.linalg.norm(w.value), slope * x_vals + intercept + 1 / np.linalg.norm(w.value), color='k', alpha=0.1)
plt.xlim([-2, 2])
plt.ylim([-2, 2])
plt.show()

このコードは、2次元空間にランダムに生成されたデータポイントをプロットし、ソフトマージンSVMによって計算された分離超平面(黒線)とマージン(灰色の領域)を表示します。

[実行結果]

解説

この例では、ソフトマージンサポートベクターマシン(SVM)を使用して、2次元空間にランダムに生成されたデータポイントを分類しています。


SVMは、データポイントを最も効果的に分離する超平面を見つけるための機械学習アルゴリズムです。

この超平面は、異なるクラスのデータポイント間のマージン(つまり、最も近いデータポイントまでの距離)を最大化します。


しかし、現実のデータはしばしば完全には分離できないため、ソフトマージンSVMは一部のデータポイントがマージンを侵害することを許容します。

これは、スラック変数ξ(xi)を導入することで実現され、これにより一部のデータポイントがマージンの「間違った側」に存在することを許容します。


この例の結果をグラフ化すると、黒線がSVMによって計算された分離超平面を表し、灰色の領域がマージンを示します。

データポイントは色でクラスが示され、一部のデータポイントがマージンを侵害していることがわかります。

これはソフトマージンSVMが許容する「間違い」を示しています。


最適化問題の目的関数は、マージンを最大化(つまり、wのノルムを最小化)し、同時にマージン侵害を最小化(つまり、スラック変数ξの合計を最小化)することです。

ここで、Cはこれら二つの目標の間のトレードオフを制御するパラメータです。

Cが大きいほど、マージン侵害をより厳しく罰することになります。

ポートフォリオ最適化問題 CVXPY

ポートフォリオ最適化問題

CVXPYを使用してポートフォリオ最適化問題を解く基本的なPythonコードを示します。

この例では、3つの異なる資産に対する投資の最適な割合を見つけることを目指しています。

まず、必要なライブラリをインポートします。

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

次に、各資産のリターンとリスク(ここでは標準偏差)を表すデータを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 資産のリターン
returns = np.array([0.1, 0.2, 0.15])

# 資産のリスク(標準偏差)
risks = np.array([0.05, 0.1, 0.08])

# 資産間の相関係数
correlation = np.array([
[1, 0.2, 0.5],
[0.2, 1, 0.3],
[0.5, 0.3, 1]
])

# 共分散行列を計算
cov_matrix = np.outer(risks, risks) * correlation

次に、CVXPYを使用して最適化問題を定義します。

ここでは、リターンを最大化し、リスク(ここではポートフォリオの標準偏差)を制約としています。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 投資の割合を表す変数
weights = cp.Variable(len(returns))

# リターンを最大化する問題を定義
objective = cp.Maximize(weights @ returns)

# 制約条件を定義
constraints = [cp.sum(weights) == 1,
weights >= 0,
cp.quad_form(weights, cov_matrix) <= 0.05**2]

# 問題を定義
problem = cp.Problem(objective, constraints)

最後に、問題を解き、最適な投資の割合を表示します。

1
2
3
4
5
# 問題を解く
problem.solve()

# 最適な投資の割合を表示
print(weights.value)

このコードは、与えられたリターンとリスクに基づいて、3つの資産に対する最適な投資の割合を計算します。

制約条件は、全ての投資の割合の合計が1(つまり、全ての資産に対する投資の割合)であることと、ポートフォリオのリスクが特定の値以下であることを保証します。

最後に、各資産の投資の割合をグラフ化します。

1
2
3
4
plt.bar(range(len(weights.value)), weights.value)
plt.xlabel('Assets')
plt.ylabel('Investment proportion')
plt.show()

このグラフは、各資産に対する最適な投資の割合を視覚的に示しています。

[実行結果]

栄養最適化 CVXPY

栄養最適化

食事に関する最適化問題の一つとして、特定の栄養素を必要量摂取しつつ、食事のコストを最小化する問題があります。

以下に、この問題をCVXPYを用いて解く例を示します。

まず、必要なライブラリをインポートします。

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

次に、問題のパラメータを定義します。ここでは、3つの食品(リンゴ、バナナ、オレンジ)と2つの栄養素(ビタミンCとカリウム)を考えます。

1
2
3
4
5
6
7
8
# 各食品のコスト(円)
costs = np.array([100, 50, 80])

# 各食品のビタミンCとカリウムの含有量
nutrients = np.array([[0.5, 0.2], [0.1, 0.3], [0.2, 0.2]])

# 必要なビタミンCとカリウムの量
required_nutrients = np.array([1.0, 0.5])

CVXPYを用いて最適化問題を定義します。

1
2
3
4
5
6
7
# 食品の購入量を表す変数
x = cp.Variable(3, nonneg=True)

# コスト最小化問題を定義
objective = cp.Minimize(costs @ x)
constraints = [nutrients.T @ x >= required_nutrients, x >= 0]
problem = cp.Problem(objective, constraints)

最適化問題を解きます。

1
problem.solve()

最適な購入量を表示します。

1
2
3
print(f"Optimal purchase quantity for Apple: {x.value[0]}")
print(f"Optimal purchase quantity for Banana: {x.value[1]}")
print(f"Optimal purchase quantity for Orange: {x.value[2]}")

最後に、この問題とその解をグラフ化します。

ただし、3つ以上の食品を扱う場合、それら全てを一つのグラフに描画することは難しいため、各食品の最適な購入量を棒グラフで表示します。

1
2
3
4
plt.bar(['Apple', 'Banana', 'Orange'], x.value)
plt.xlabel('Food')
plt.ylabel('Optimal purchase quantity')
plt.show()

このコードは、リンゴ、バナナ、オレンジの最適な購入量を示す棒グラフをプロットします。

[実行結果]

値引き最適化 PuLP

値引き最適化

値引き最適化問題とは、特定の制約条件下で最大の利益を得るための最適な値引き率を求める問題です。

ここでは、ある店が3つの商品を販売していて、それぞれの商品に対する最大の値引き率と、それぞれの商品がもたらす利益が異なるという状況を考えてみましょう。

まずは、必要なライブラリをインポートします。

1
2
3
from pulp import *
import matplotlib.pyplot as plt
import numpy as np

次に、問題を定義します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 問題の定義
prob = LpProblem("Discount Optimization", LpMaximize)

# 変数の定義
discounts = ['product_1', 'product_2', 'product_3']
discount_vars = LpVariable.dicts("Discount", discounts, 0, 1)

# 利益の定義
profits = {'product_1': 100, 'product_2': 200, 'product_3': 300}

# 目的関数の定義
prob += lpSum([profits[i]*discount_vars[i] for i in discounts])

# 制約条件の定義
prob += lpSum([discount_vars[i] for i in discounts]) <= 1.5, "Total Discount Constraint"

# 問題の解決
prob.solve()

最後に、結果を表示し、グラフ化します。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 結果の表示
for v in prob.variables():
print(v.name, "=", v.varValue)

# グラフ化
plt.figure(figsize=(8,6))
plt.bar(range(len(discounts)), [value(var) for var in prob.variables()])

plt.xticks(range(len(discounts)), [var.name for var in prob.variables()])
plt.xlabel('Products')
plt.ylabel('Discount Rate')
plt.title('Optimal Discount Rates for Products')
plt.show()

このコードは、3つの商品に対する最適な値引き率を求め、それを棒グラフで表示します。

制約条件は、全商品の値引き率の合計が1.5以下であることを指定しています。

また、目的関数は各商品の利益と値引き率の積の合計を最大化することを目指しています。

これにより、最大の利益を得るための最適な値引き率が求められます。

[実行結果]

患者スケジューリング問題 PuLP

患者スケジューリング問題

患者スケジューリング問題は、医療機関でのリソース(医師、看護師、診療室など)を最適に割り当てるための問題です。

ここでは、あるクリニックでの医師のスケジューリング問題を考え、それをPuLPを用いて解く例を示します。

まず、以下のような仮定を置きます:

  • クリニックには3人の医師(A、B、C)がいます。
  • 1週間(月曜日から金曜日)のスケジューリングを考えます。
  • 1日に各医師は最大1シフト(午前または午後)しか働けません。
  • 1日に最低2人の医師が必要です。
  • 各医師は1週間に最大4日しか働けません。
  • 各医師は1週間に最低2日は働く必要があります。

この問題を解くためのPythonコードは以下の通りです:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pulp import *

# 医師と日付のリストを作成
doctors = ['A', 'B', 'C']
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']

# 問題を定義
prob = LpProblem("Doctors_Scheduling", LpMinimize)

# 変数を定義(各医師が各日に働くかどうか)
x = LpVariable.dicts("x", (doctors, days), cat='Binary')

# 目的関数を定義(医師の働く日数を最小化)
prob += lpSum(x[doctor][day] for doctor in doctors for day in days)

# 制約を定義
for day in days:
prob += lpSum(x[doctor][day] for doctor in doctors) >= 2 # 1日に最低2人の医師が必要

for doctor in doctors:
prob += lpSum(x[doctor][day] for day in days) <= 4 # 各医師は1週間に最大4日しか働けない
prob += lpSum(x[doctor][day] for day in days) >= 2 # 各医師は1週間に最低2日は働く必要があります

# 問題を解く
prob.solve()

# 結果を表示
for v in prob.variables():
print(v.name, "=", v.varValue)

このコードは、各医師が1週間で働く日数を最小化するスケジュールを作成します。

制約として、各日に最低2人の医師が必要であり、各医師は1週間に最大4日しか働けず、最低でも2日は働く必要があるという条件を設けています。

[実行結果]
x_A_Fri = 1.0
x_A_Mon = 1.0
x_A_Thu = 0.0
x_A_Tue = 1.0
x_A_Wed = 1.0
x_B_Fri = 1.0
x_B_Mon = 1.0
x_B_Thu = 1.0
x_B_Tue = 0.0
x_B_Wed = 0.0
x_C_Fri = 0.0
x_C_Mon = 0.0
x_C_Thu = 1.0
x_C_Tue = 1.0
x_C_Wed = 1.0

グラフ化

結果をグラフ化するためには、matplotlibなどのライブラリを使用します。

以下に、結果をヒートマップとして表示する例を示します:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np

# 結果を配列に格納
result = np.zeros((len(doctors), len(days)))
for v in prob.variables():
doctor, day = v.name.split("_")[1:]
result[doctors.index(doctor)][days.index(day)] = v.varValue

# ヒートマップを表示
plt.imshow(result, cmap='hot', interpolation='nearest')
plt.colorbar(label='Shifts')
plt.xticks(np.arange(len(days)), days)
plt.yticks(np.arange(len(doctors)), doctors)
plt.show()

このコードは、各医師が各日に働くかどうかを色で表したヒートマップを作成します。

医師が働く日は明るい色、働かない日は暗い色で表示されます。

[実行結果]

薬剤最適化問題 PuLP

薬剤最適化問題

薬剤最適化問題として、以下のようなシナリオを考えてみましょう。


ある病院が、2つの薬剤AとBを患者に投与しています。

これらの薬剤はそれぞれ特定の2つの栄養素を含んでいます。

薬剤Aは1単位あたり栄養素Xを3単位栄養素Yを2単位含み、薬剤Bは1単位あたり栄養素Xを4単位栄養素Yを3単位含んでいます。

患者は1日に栄養素Xを最低12単位、栄養素Yを最低15単位摂取する必要があります。

薬剤AとBのコストはそれぞれ1単位あたり5ドル7ドルです。

病院は患者に必要な栄養素を提供しつつ、コストを最小限に抑えたいと考えています。


この問題は線形計画問題として定式化でき、PuLPを使用して解くことができます。

以下にPythonコードを示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pulp import LpProblem, LpMinimize, LpVariable

# 問題の定義
prob = LpProblem("MedicineOptimization", LpMinimize)

# 変数の定義
A = LpVariable("Medicine_A", 0, None) # 薬剤Aの単位数
B = LpVariable("Medicine_B", 0, None) # 薬剤Bの単位数

# 目的関数の定義 (薬剤AとBのコストの最小化)
prob += 5 * A + 7 * B

# 制約条件の定義
prob += 3 * A + 4 * B >= 12 # 栄養素Xの最低摂取量
prob += 2 * A + 3 * B >= 15 # 栄養素Yの最低摂取量

# 問題の解法
prob.solve()

print("Optimal Units of Medicine A: ", A.varValue)
print("Optimal Units of Medicine B: ", B.varValue)

このコードは、薬剤AとBの最適な単位数を計算します。

これにより、病院は患者に必要な栄養素を提供しつつ、コストを最小限に抑えることができます。

[実行結果]
Optimal Units of Medicine A:  0.0
Optimal Units of Medicine B:  5.0

グラフ化

次に、この結果をグラフ化するためのPythonコードを示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import matplotlib.pyplot as plt
import numpy as np

# 栄養素XとYの最低摂取量
min_X = 12
min_Y = 15

# 薬剤AとBの単位数の範囲
range_A = np.linspace(0, 10, 100)
range_B = np.linspace(0, 10, 100)

# 栄養素XとYの摂取量
X = 3 * range_A + 4 * range_B
Y = 2 * range_A + 3 * range_B

plt.figure(figsize=(8, 6))
plt.plot(range_A, (min_X - 3 * range_A) / 4, label="Nutrient X")
plt.plot(range_A, (min_Y - 2 * range_A) / 3, label="Nutrient Y")
plt.xlim(0, 10)
plt.ylim(0, 10)
plt.xlabel("Units of Medicine A")
plt.ylabel("Units of Medicine B")
plt.legend()
plt.grid(True)
plt.show()

このグラフは、薬剤AとBの単位数に対する栄養素XとYの摂取量を示しています。

栄養素XとYの最低摂取量を満たすために必要な薬剤AとBの単位数を視覚的に理解することができます。

[実行結果]

ポイントオブセール最適化 PuLP

ポイントオブセール最適化

ポイントオブセール(POS)最適化問題は、商品の配置や在庫管理など、販売効率を最大化するための問題です。

ここでは、簡単な在庫管理問題を例に取り、PythonのPuLPライブラリを使用して解きます。

問題設定:
  • 商品A、B、Cがあり、それぞれの在庫数は最大10個とします。
  • 商品A、B、Cの利益はそれぞれ100円、200円、300円とします。
  • 予算は2000円とし、この予算内で最大の利益を得られるように在庫を管理します。

この問題をPuLPで解くコードは以下の通りです:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pulp import LpMaximize, LpProblem, LpStatus, lpSum, LpVariable

# 問題の定義
model = LpProblem(name="small-shop-problem", sense=LpMaximize)

# 変数の定義
x = {i: LpVariable(name=f"x{i}", lowBound=0, upBound=10, cat="Integer") for i in range(1, 4)}

# 利益の定義
profit = {1: 100, 2: 200, 3: 300}

# 目的関数
model += lpSum(profit[i] * x[i] for i in range(1, 4))

# 制約条件
model += (lpSum(x[i] for i in range(1, 4)) <= 2000, "budget_constraint")

# 問題の解
status = model.solve()

for var in x.values():
print(f"{var.name}: {var.value()}")

print(f"Optimal profit: {model.objective.value()}")

このコードは、在庫数と利益を最大化するための最適な商品の組み合わせを求めます。

[実行結果]
x1: 10.0
x2: 10.0
x3: 10.0
Optimal profit: 6000.0

グラフ化

次に、この問題の解をグラフ化します。

matplotlibを使用して、各商品の最適な在庫数を棒グラフで表示します:

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt

# 商品名
items = ['Item A', 'Item B', 'Item C']

# 最適な在庫数
optimal_values = [x[i].value() for i in range(1, 4)]

plt.bar(items, optimal_values)
plt.xlabel('Items')
plt.ylabel('Optimal Stock')
plt.title('Optimal Stock Level for Each Item')
plt.show()

このグラフは、各商品の最適な在庫数を視覚的に示しています。

[実行結果]

効率的フロンティア最適化 PuLP

効率的フロンティア最適化

効率的フロンティアの最適化問題を定義します。

この問題では、与えられたリスクレベルで最大のリターンを達成する投資ポートフォリオを見つけることが目的です。

以下に示すように、PythonのPuLPライブラリを使用してこの問題を解くことができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pulp import *
import numpy as np
import matplotlib.pyplot as plt

# 各投資商品のリターンとリスク
returns = {'A': 0.1, 'B': 0.12, 'C': 0.10, 'D': 0.07}
risks = {'A': 0.05, 'B': 0.07, 'C': 0.06, 'D': 0.03}

# 投資商品のリスト
assets = list(returns.keys())

# リスクの上限
risk_limit = 0.05

# 問題の定義
prob = LpProblem("Efficient Frontier", LpMaximize)

# 変数の定義
x = LpVariable.dicts("x", assets, 0)

# 目的関数
prob += lpSum([returns[i]*x[i] for i in assets])

# 制約条件
prob += lpSum([risks[i]*x[i] for i in assets]) <= risk_limit
prob += lpSum([x[i] for i in assets]) == 1

# 問題の解
prob.solve()

# 結果の表示
for i in assets:
print(f"Investment in asset {i}: {x[i].varValue}")

このコードは、与えられたリスクレベルで最大のリターンを達成する投資ポートフォリオを見つけます。

結果は、各投資商品に対する投資比率として表示されます。

[実行結果]
Investment in asset A: 1.0
Investment in asset B: 0.0
Investment in asset C: 0.0
Investment in asset D: 0.0

グラフ化

次に、効率的フロンティアをグラフ化します。

これは、可能なすべての投資ポートフォリオのリスクとリターンをプロットしたものです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# リスクとリターンのリスト
risks_list = np.linspace(0.01, 0.1, 100)
returns_list = []

for risk_limit in risks_list:
prob = LpProblem("Efficient Frontier", LpMaximize)
x = LpVariable.dicts("x", assets, 0)
prob += lpSum([returns[i]*x[i] for i in assets])
prob += lpSum([risks[i]*x[i] for i in assets]) <= risk_limit
prob += lpSum([x[i] for i in assets]) == 1
prob.solve()
returns_list.append(value(prob.objective))

# グラフの描画
plt.plot(risks_list, returns_list)
plt.xlabel('Risk')
plt.ylabel('Return')
plt.title('Efficient Frontier')
plt.show()
[実行結果]

このグラフは、リスクとリターンのトレードオフを視覚的に示しています。

効率的フロンティアは、与えられたリスクレベルで達成可能な最大のリターンを示しています。

物流最適化問題 PuLP

物流最適化問題

物流最適化問題の一つとして、輸送問題を考えてみましょう。

輸送問題は、複数の供給地点から複数の需要地点への最小コストの輸送計画を求める問題です。

以下に、PythonのPuLPを用いて輸送問題を解く例を示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from pulp import LpProblem, LpMinimize, LpVariable, lpSum
import pandas as pd
import matplotlib.pyplot as plt

# データの設定
# 供給地点と供給量
supply_points = {'Factory1': 500, 'Factory2': 600}
# 需要地点と需要量
demand_points = {'Shop1': 300, 'Shop2': 400, 'Shop3': 400}
# 供給地点から需要地点への輸送コスト
costs = {
'Factory1': {'Shop1': 2, 'Shop2': 4, 'Shop3': 5},
'Factory2': {'Shop1': 3, 'Shop2': 1, 'Shop3': 3}
}

# 問題の定義
prob = LpProblem('Transportation', LpMinimize)

# 変数の定義
vars = {
i: {
j: LpVariable(f"x({i},{j})", lowBound=0)
for j in demand_points
}
for i in supply_points
}

# 目的関数の定義
prob += lpSum(costs[i][j] * vars[i][j] for i in supply_points for j in demand_points)

# 制約条件の定義
for i in supply_points:
prob += lpSum(vars[i][j] for j in demand_points) <= supply_points[i]
for j in demand_points:
prob += lpSum(vars[i][j] for i in supply_points) >= demand_points[j]

# 問題の解法
prob.solve()

# 結果の表示
for v in prob.variables():
print(v.name, "=", v.varValue)

# 結果のグラフ化
df = pd.DataFrame([(v.name, v.varValue) for v in prob.variables()], columns=['Variable', 'Value'])
df.plot(kind='bar', x='Variable', y='Value')
plt.show()

このコードは、2つの工場から3つの店舗への最小コストの輸送計画を求めます。

各工場から各店舗への輸送コストと供給量、需要量を元に、PuLPを用いて最適化問題を解きます。

最後に、各ルートの輸送量を棒グラフで表示します。

[実行結果]

ソースコード解説

1行目から6行目:

必要なライブラリのインポートを行います。

pulpは線形最適化モデリングライブラリであり、pandasとmatplotlibはデータ処理とグラフ表示のためのライブラリです。


9行目から11行目:

輸送問題で必要なデータの設定を行います。

供給地点と供給量、需要地点と需要量、および供給地点から需要地点への輸送コストを辞書として定義しています。


14行目:

LpProblemオブジェクトを作成し、最小化問題を定義します。

‘Transportation’は問題の名前で、LpMinimizeは最小化問題を指定しています。


17行目から22行目:

変数の定義を行います。

変数は「供給地点iから需要地点jへの輸送量」として定義され、LpVariableオブジェクトとして作成されます。

変数名は”x(i,j)”となります。


25行目:

目的関数を定義します。輸送コストと変数の積の総和として定義され、最小化対象となります。


28行目から30行目:

制約条件を定義します。各供給地点からの輸送量は供給量以下でなければならず、各需要地点への輸送量は需要量以上でなければなりません。


33行目:

prob.solve()を呼び出して、問題を解きます。

具体的な最適解が計算されます。


36行目から38行目:

解の結果を表示します。

各変数の値(輸送量)が表示されます。


41行目から45行目:

結果を棒グラフとして表示します。

解の各変数の値をDataFrameに格納し、pandasとmatplotlibを使用して棒グラフを描画します。