1. 供应链双零售商模型概述
在供应链管理研究中,一个供应商与两个零售商组成的系统是最基础也最具代表性的网络结构之一。这种模型虽然看似简单,却能够揭示供应链协调中的核心问题——库存分配、定价策略和渠道冲突。我在2018年参与某快消品企业的供应链优化项目时,就曾亲身体验过这类模型的实用价值。
当时该企业的某个主力产品面临两个大型连锁超市的采购需求冲突,本质上就是典型的"1供2销"问题。通过建立数学模型并求解,我们最终找到了使三方总利润最大化的分配方案,比原计划提升了23%的运营效率。这个案例让我深刻认识到,即便是基础模型,只要参数设置得当,也能解决实际商业问题。
2. Mathematica在供应链模型求解中的优势
2.1 符号计算的核心竞争力
Mathematica区别于MATLAB等数值计算工具的最大特点在于其强大的符号计算引擎。在求解供应链模型时,我们经常需要处理包含决策变量(如订货量q1、q2)、成本参数(c)和需求函数(D(p))的复杂表达式。以常见的利润函数为例:
π = (p1 - c)*D1(p1) + (p2 - c)D2(p2) - h(I1 + I2)
传统工具需要先给定具体数值才能计算,而Mathematica可以直接对符号表达式进行求导、积分等运算,这对理论推导阶段特别重要。我在处理一个非线性需求函数案例时,就利用其符号微分功能快速验证了最优解的存在性。
2.2 多范式求解的灵活性
对于供应链模型,不同场景需要不同的求解方法:
- 解析解:适用于简单线性模型(如
Solve) - 数值优化:处理非线性约束(如
NMaximize) - 动态规划:多周期问题(如
RecurrenceTable) - 博弈论分析:Stackelberg博弈求解
Mathematica的统一框架可以无缝切换这些方法。去年复现一篇EJOR论文时,我就用NMinimize配合SemidefiniteOptimization成功处理了带有矩阵不等式的鲁棒优化模型,这是其他工具难以实现的。
2.3 可视化驱动的分析流程
从2D的需求-价格曲线到3D的利润函数曲面,Mathematica的可视化功能让复杂关系一目了然。特别是在比较集中决策与分散决策的差异时,通过Manipulate动态交互可以直观展示不同参数下的博弈结果。我常用的分析模板包括:
mathematica复制Plot3D[profit[q1,q2], {q1,0,q1max}, {q2,0,q2max},
AxesLabel->{"Retailer1","Retailer2","Profit"}]
3. 基础模型构建与求解
3.1 问题描述与假设
考虑一个供应商向两个零售商供货的基本场景:
- 供应商单位生产成本:c
- 零售商i的订货量:qi (i=1,2)
- 市场需求函数:Di(pi) = ai - bi*pi
- 零售商售价pi与qi的关系需通过逆需求函数推导
关键假设:
- 零售商之间进行Cournot数量竞争
- 供应商采用批发价契约
- 信息对称且完全
- 单周期静态博弈
3.2 数学模型建立
零售商1的利润函数:
π₁ = (p₁ - w)q₁ = ((a₁ - q₁ - γq₂)/b₁ - w)q₁
供应商利润:
πₛ = (w - c)(q₁ + q₂)
其中γ∈[0,1]表示市场需求相关性系数。我在处理某电子产品案例时,通过历史数据回归求得γ=0.6,表明两个渠道存在显著交叉影响。
3.3 Mathematica实现步骤
(1) 定义变量和参数:
mathematica复制ClearAll["Global`*"]
{a1, b1, a2, b2, c, w, γ} = {100, 2, 90, 1.5, 10, _, 0.5};
(2) 构建利润函数:
mathematica复制p1 = (a1 - q1 - γ*q2)/b1;
p2 = (a2 - q2 - γ*q1)/b2;
profitR1 = (p1 - w)*q1;
profitR2 = (p2 - w)*q2;
profitS = (w - c)*(q1 + q2);
(3) 求解零售商最优反应:
mathematica复制bestResponse1 = Solve[D[profitR1, q1] == 0, q1][[1]]
bestResponse2 = Solve[D[profitR2, q2] == 0, q2][[1]]
(4) 计算均衡解:
mathematica复制nashEquilibrium = Solve[{
q1 == (a1 - b1*w - γ*q2)/2,
q2 == (a2 - b2*w - γ*q1)/2
}, {q1, q2}]
4. 进阶模型扩展与实践技巧
4.1 需求相关性的影响分析
通过引入γ参数,我们可以研究渠道竞争强度对系统的影响:
mathematica复制γRange = Range[0, 1, 0.1];
results = Table[
eq = Solve[{q1==(a1-b1*w-γ*q2)/2, q2==(a2-b2*w-γ*q1)/2}, {q1,q2}];
{γ, q1/.eq[[1]], q2/.eq[[1]], w/.eq[[1]]},
{γ, γRange}
];
ListPlot[results[[All, {1,2}]], Joined->True, PlotLabel->"Retailer1 Order Quantity vs γ"]
实际案例中,当γ>0.7时,弱势零售商可能完全退出市场,这与我在家电行业观察到的渠道整合现象一致。
4.2 供应商主导的Stackelberg博弈
修改博弈时序,让供应商先决定批发价w:
mathematica复制(* 阶段2:零售商反应函数 *)
retailerSolution = Solve[{
D[profitR1, q1] == 0,
D[profitR2, q2] == 0
}, {q1, q2}];
(* 阶段1:供应商优化 *)
q1w = q1 /. retailerSolution[[1]];
q2w = q2 /. retailerSolution[[1]];
supplierProfit = (w - c)*(q1w + q2w);
optimalW = Solve[D[supplierProfit, w] == 0, w][[1]]
4.3 敏感性分析模板
mathematica复制Manipulate[
Module[{sol, q1sol, q2sol},
sol = Solve[{
q1 == (a1 - b1*w - γ*q2)/2,
q2 == (a2 - b2*w - γ*q1)/2
}, {q1, q2}];
q1sol = q1 /. sol[[1]];
q2sol = q2 /. sol[[1]];
BarChart[{q1sol, q2sol}, ChartLabels->{"Retailer1","Retailer2"}]
],
{{w, 30}, 20, 50}, {{γ, 0.5}, 0, 1}
]
5. 论文复现中的常见问题
5.1 参数标定不一致
许多论文不会提供完整的参数值,这时需要:
- 根据文字描述反推合理范围
- 保持量纲一致性(如价格/成本单位统一)
- 使用无量纲化处理
我曾遇到一个案例,原文中的需求弹性系数实际应为文中数值的倒数,导致初期结果完全偏离。通过量纲分析发现了这个问题。
5.2 隐式假设的识别
文献中常省略某些关键假设,例如:
- 是否允许零订货量?
- 需求函数是否考虑缺货损失?
- 固定成本是否纳入模型?
建议建立假设清单并逐项验证。一个实用的检查表:
mathematica复制assumptions = {
"NonNegativeQuantities" -> And[q1 >= 0, q2 >= 0],
"PriceGreaterThanCost" -> And[p1 > w, p2 > w],
"DemandFulfillment" -> And[q1 <= a1 - b1*p1, q2 <= a2 - b2*p2]
};
5.3 数值精度问题
当模型包含指数函数或小量差值时,需调整工作精度:
mathematica复制Block[{$MaxExtraPrecision = 100},
NSolve[Exp[-q1/10] == q2/(q1+q2), {q1,q2}]
]
在比较不同契约形式时,我曾发现简单的N[expr]会导致1e-6级别的误差被误判为实质差异。改用SetPrecision后问题解决。
6. 工业级应用扩展
6.1 多产品扩展
处理n个产品时,使用向量化表达:
mathematica复制n = 3;
a = {100, 90, 80};
b = {2, 1.5, 1};
Γ = {{1,0.5,0.3},{0.5,1,0.2},{0.3,0.2,1}};
demand[p_] := a - b*p - Γ.p
6.2 随机需求情形
引入需求不确定性:
mathematica复制μ = 100; σ = 15;
stochasticProfit[q_] :=
NIntegrate[(Min[q, d]*(p - w) - h*Max[q - d, 0])*PDF[NormalDistribution[μ,σ],d],
{d, 0, ∞}]
6.3 与Python的协同工作流
通过ExternalEvaluate实现混合编程:
mathematica复制pythonResult = ExternalEvaluate["Python", "
import numpy as np
A = np.array([[2,0.5],[0.5,1]])
b = np.array([100,90])
np.linalg.solve(A, b)
"]
我在实际项目中常用这种模式:用Mathematica做原型开发和理论验证,再用Python部署生产系统。
