食事計画(線形計画問題)

食事計画(線形計画問題)

CVXPYを使って線形計画問題を解きます。

ここでは、食事計画の問題を考えます。

この問題では、複数の食品から適切な組み合わせを選んで、特定の栄養要件を満たしつつ、コストを最小限に抑えることを目的とします。

問題設定

食品の種類:

  1. チキン (Chicken)
  2. 牛肉 (Beef)
  3. 豆 (Beans)

各食品のコストと栄養素含有量は以下の通り:

  • チキン: コスト 2ドル、タンパク質 20g、脂肪 5g、炭水化物 0g
  • 牛肉: コスト 3ドル、タンパク質 15g、脂肪 10g、炭水化物 0g
  • 豆: コスト 1ドル、タンパク質 10g、脂肪 2g、炭水化物 20g

栄養要件:

  • タンパク質: 最低 30g
  • 脂肪: 最低 10g、最大 20g
  • 炭水化物: 最低 20g

解法

この問題をCVXPYを使って解きます。

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
import cvxpy as cp
import numpy as np

# 各食品のコストと栄養素含有量
cost = np.array([2, 3, 1])
protein = np.array([20, 15, 10])
fat = np.array([5, 10, 2])
carbs = np.array([0, 0, 20])

# 栄養要件
min_protein = 30
min_fat = 10
max_fat = 20
min_carbs = 20

# 食品の量 (変数)
x = cp.Variable(3, nonneg=True)

# コスト最小化
objective = cp.Minimize(cost @ x)

# 制約条件
constraints = [
protein @ x >= min_protein,
fat @ x >= min_fat,
fat @ x <= max_fat,
carbs @ x >= min_carbs
]

# 問題の定義と解決
problem = cp.Problem(objective, constraints)
problem.solve()

# 結果の表示
print(f"Status: {problem.status}")
print(f"Optimal value: {problem.value:.2f} dollars")
print(f"Optimal solution: {x.value}")
print(f"Chicken: {x.value[0]:.2f} units")
print(f"Beef: {x.value[1]:.2f} units")
print(f"Beans: {x.value[2]:.2f} units")

このコードでは、以下の手順で食事計画問題を解きます:

  1. 各食品のコスト栄養素含有量を定義します。
  2. 栄養要件を設定します。
  3. 変数 x を定義し、各食品の量を表します(非負制約)。
  4. 目的関数コストの最小化として定義します。
  5. 栄養要件に基づく制約を設定します。
  6. 問題を定義し、解決します。
  7. 最適なコスト食品の量を表示します。

このコードを実行すると、栄養要件を満たしつつコストを最小限に抑える最適な食品の組み合わせが得られます。

[実行結果]

Status: optimal
Optimal value: 3.72 dollars
Optimal solution: [0.64 0.48 1.  ]
Chicken: 0.64 units
Beef: 0.48 units
Beans: 1.00 units

ソースコード解説

ソースコードの詳細は以下の通りです。

1. ライブラリのインポート

1
2
import cvxpy as cp
import numpy as np

ここでは、最適化問題を解くためのCVXPYライブラリと、数値計算を行うためのNumPyライブラリをインポートしています。

2. 各食品のコストと栄養素含有量の定義

1
2
3
4
cost = np.array([2, 3, 1])
protein = np.array([20, 15, 10])
fat = np.array([5, 10, 2])
carbs = np.array([0, 0, 20])

ここでは、各食品(チキン、ビーフ、豆)のコストと栄養素(タンパク質、脂肪、炭水化物)の含有量を配列として定義しています。

例えば、チキンのコストは2ドルで、タンパク質が20グラム、脂肪が5グラム含まれています。

3. 栄養要件の定義

1
2
3
4
min_protein = 30
min_fat = 10
max_fat = 20
min_carbs = 20

ここでは、最低限必要なタンパク質、脂肪の最小および最大量、最低限必要な炭水化物の量を定義しています。

4. 変数の定義

1
x = cp.Variable(3, nonneg=True)

ここでは、最適化問題の変数である各食品の量を表すベクトル x を定義しています。
この変数は非負(負の値を取らない)であることが指定されています。

5. コスト最小化の目的関数

1
objective = cp.Minimize(cost @ x)

ここでは、総コストを最小化する目的関数を定義しています。
cost @ x はコストと食品の量の内積を計算し、これを最小化します。

6. 制約条件の定義

1
2
3
4
5
6
constraints = [
protein @ x >= min_protein,
fat @ x >= min_fat,
fat @ x <= max_fat,
carbs @ x >= min_carbs
]

ここでは、栄養要件に基づく制約条件を定義しています。
具体的には、次の制約を課しています:

  • 総タンパク質が30グラム以上
  • 総脂肪が10グラム以上20グラム以下
  • 総炭水化物が20グラム以上

7. 最適化問題の定義と解決

1
2
problem = cp.Problem(objective, constraints)
problem.solve()

ここでは、目的関数制約条件をもとに最適化問題を定義し、これを解決しています。
problem.solve() によって、最適解が計算されます。

8. 結果の表示

1
2
3
4
5
6
print(f"Status: {problem.status}")
print(f"Optimal value: {problem.value:.2f} dollars")
print(f"Optimal solution: {x.value}")
print(f"Chicken: {x.value[0]:.2f} units")
print(f"Beef: {x.value[1]:.2f} units")
print(f"Beans: {x.value[2]:.2f} units")

ここでは、最適化のステータス最適なコスト、各食品の最適な量を表示しています。

結果解説

[実行結果]

Status: optimal
Optimal value: 3.72 dollars
Optimal solution: [0.64 0.48 1.  ]
Chicken: 0.64 units
Beef: 0.48 units
Beans: 1.00 units
  • Status: optimal:
    問題が最適に解決されたことを示しています。
  • Optimal value: 3.72 dollars:
    最適な食品の組み合わせのコストが3.72ドルであることを示しています。
  • Optimal solution:
    各食品の最適な量を示しています。
    具体的には、チキン0.64単位、ビーフ0.48単位、豆1.00単位です。

これにより、指定された栄養要件を満たしつつ、コストを最小限に抑えるための最適な食事計画が得られます。