Mímisbrunnr知恵の泉

← 数理最適化 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:線形計画の双対性 | 関連:スケジューリング・配送のモデル化

要点(BLUF)

概念 ── なぜ感度分析か

実務のデータ(資源量・利益単価)はたいてい不確かで、後で変わる。そのたびに解き直すのは非効率。感度分析は 最適解の「効いている構造」を読み解き、小さな変化への反応を解析的に与える。LP の双対性(線形計画の双対性)がそのまま道具になる。

影の価格(右辺の変化)

制約 ii の右辺 bib_iΔ\Delta だけ動かすと、最適値は近似的に

z(bi+Δ)z(bi)+yiΔz^\star(b_i + \Delta) \approx z^\star(b_i) + y_i^\star \,\Delta

yiy_i^\star影の価格(shadow price)=双対最適解。経済的には「資源 ii をあと1単位手に入れたら利益がいくら増えるか」=資源の限界価値。

ただしこの線形近似が成り立つのは 許容範囲(right-hand-side ranging) 内だけ。範囲を超えると最適基底(どの頂点か)が変わり、影の価格も変わる。

被約費用(目的係数の変化)

非基底変数 xjx_j(最適で0の変数)の 被約費用 cˉj\bar c_j は、「その製品を無理に1単位作ると利益がいくら減るか」。目的係数 cjc_jcˉj\bar c_j を超えて改善しない限り、xjx_j は基底に入らず最適解の構成は変わらない(目的係数の許容範囲)。

Pythonで影の価格を確認

scipy の linprog 結果から ineqlin.marginals で影の価格が取れる(符号は最小化基準なので反転)。さらに材料の右辺を 100→101 に増やして、利益が影の価格どおり増えるか実測する。

from scipy.optimize import linprog

c = [-40, -30]
A_ub = [[2, 1], [1, 1]]   # 機械時間, 材料
b_ub = [120, 100]
bounds = [(0, None), (0, None)]

res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method="highs")
shadow = -res.ineqlin.marginals   # 最大化に直すため符号反転
print(f"機械時間の影の価格 = {shadow[0]:.1f}")
print(f"材料の影の価格   = {shadow[1]:.1f}")

# 材料を 100 -> 101 に1単位増やして利益の増分を実測
res2 = linprog(c, A_ub=A_ub, b_ub=[120, 101], bounds=bounds, method="highs")
print(f"利益: {-res.fun:.0f} -> {-res2.fun:.0f}  (増分 {(-res2.fun)-(-res.fun):.1f})")

実行結果:

機械時間の影の価格 = 10.0
材料の影の価格   = 20.0
利益: 3200 -> 3220  (増分 20.0)

材料の影の価格は 20。実際に材料を1単位増やすと利益が 3200→3220 と ちょうど 20 増える。影の価格の予測どおり。機械時間の影の価格 10 は「機械をあと1時間使えれば利益が10増える」を意味し、設備投資の判断材料になる。

数式の直観的意味

影の価格 yiy_i^\star は最適値 z(b)z^\star(b)bib_i に関する 偏微分(限界価値) z/bi\partial z^\star / \partial b_i。最適基底が変わらない範囲では zz^\starbb の線形関数なので、傾き yiy_i^\star が一定 ── これが「許容範囲内では影の価格は一定」の正体。範囲の端で基底が切り替わると、z(b)z^\star(b) は折れ線(区分線形・凹)になり、傾き(影の価格)が階段状に変わる。だから「資源を大量に買えば買うほど割に合う」とはならず、限界価値は逓減する。これは経済学の限界分析そのもの。

⚠️ よくある誤解・落とし穴

関連ノート