1. 项目概述:供应链双零售商模型的数学求解与复现
这个项目源于我在研究供应链管理时遇到的一个经典问题:单一供应商同时向两个零售商供货的协调优化。这种模型在实际商业中极为常见——比如某食品厂同时给连锁超市和社区便利店供货,或者电子元件制造商同时服务品牌商和分销商。问题的核心在于如何在供需关系中平衡各方利益,实现整体效益最大化。
我选择用Mathematica来完成这个模型的求解和论文复现,主要看中它在符号计算和数值优化方面的独特优势。相比Python或MATLAB,Mathematica的符号引擎能直接处理复杂的约束条件,可视化功能可以直观展示供应链参数之间的关系,这对于验证模型正确性特别有帮助。下面我就把整个复现过程拆解成可操作的步骤,包括模型建立、参数设置、求解技巧和结果分析。
2. 模型构建与数学表达
2.1 基础假设与变量定义
我们先明确这个供应链模型的基本设定:
- 单一供应商生产单一产品,单位生产成本为c
- 两个零售商分别记为R1和R2,其市场需求函数为:
- R1: q₁ = a₁ - b₁p₁ + θ(p₂ - p₁)
- R2: q₂ = a₂ - b₂p₂ + θ(p₁ - p₂)
其中θ表示两个零售商之间的价格交叉弹性
- 供应商以批发价w向零售商供货
- 零售商承担单位销售成本cr
关键提示:θ的取值直接影响模型性质。当θ=0时两个市场完全独立;当θ增大时竞争效应增强。实际应用中需要通过历史数据校准这个参数。
2.2 利润函数建立
各方的利润函数如下:
供应商利润:
π_s = (w - c)(q₁ + q₂)
零售商利润:
π₁ = (p₁ - w - cr)q₁
π₂ = (p₂ - w - cr)q₂
2.3 博弈时序
这是一个典型的三阶段Stackelberg博弈:
- 供应商设定批发价w
- 零售商观察到w后,同时设定零售价p₁和p₂
- 市场需求根据价格实现
3. Mathematica实现详解
3.1 环境配置
首先确保Mathematica版本在12.0以上(新版符号计算引擎更稳定)。建议先清理工作环境:
mathematica复制ClearAll["Global`*"]
然后定义基础参数和变量:
mathematica复制vars = {w > 0, p1 > 0, p2 > 0, a1 > 0, a2 > 0, b1 > 0, b2 > 0, θ > 0, c > 0, cr > 0};
parameters = {a1 -> 100, a2 -> 80, b1 -> 1.2, b2 -> 1, θ -> 0.3, c -> 10, cr -> 5};
3.2 需求函数实现
用符号表达式定义需求函数:
mathematica复制q1 = a1 - b1*p1 + θ*(p2 - p1);
q2 = a2 - b2*p2 + θ*(p1 - p2);
3.3 逆向求解法
按照博弈时序,我们先求零售商的反应函数:
mathematica复制profit1 = (p1 - w - cr)*q1;
profit2 = (p2 - w - cr)*q2;
retailerSolution = Solve[{
D[profit1, p1] == 0,
D[profit2, p2] == 0
}, {p1, p2}];
得到的价格反应函数形式较为复杂,可以用TeXForm查看数学表达式:
mathematica复制p1Solution = p1 /. retailerSolution[[1]];
TeXForm[p1Solution]
3.4 供应商优化问题
将零售商反应函数代入供应商利润函数:
mathematica复制totalQuantity = q1 + q2 /. retailerSolution[[1]];
supplierProfit = (w - c)*totalQuantity;
optW = Solve[D[supplierProfit, w] == 0, w];
optimalW = w /. optW[[1]];
4. 结果分析与可视化
4.1 均衡解计算
代入具体参数值计算均衡解:
mathematica复制equilibrium = {
w -> optimalW,
p1 -> p1Solution,
p2 -> p2Solution
} /. parameters // N
典型输出结果:
code复制{w -> 32.456, p1 -> 58.214, p2 -> 54.782}
4.2 敏感度分析
研究交叉弹性θ对批发价的影响:
mathematica复制Plot[optimalW /. θ -> x, {x, 0, 0.8},
AxesLabel -> {"交叉弹性θ", "最优批发价w"},
PlotLabel -> "竞争强度对批发价的影响"]
4.3 利润分配分析
计算各方利润并绘制饼图:
mathematica复制finalProfit1 = profit1 /. equilibrium /. retailerSolution[[1]];
finalProfit2 = profit2 /. equilibrium /. retailerSolution[[1]];
finalSupplierProfit = supplierProfit /. equilibrium;
PieChart[{
{"供应商", finalSupplierProfit},
{"零售商1", finalProfit1},
{"零售商2", finalProfit2}
}, ChartLabels -> Automatic]
5. 复现中的关键问题与解决方案
5.1 符号计算失败处理
当表达式过于复杂时,可能会遇到无法解析的情况。建议:
- 分步计算,简化中间表达式
- 使用Together或Simplify函数化简
- 必要时指定变量约束条件
5.2 多解筛选
博弈模型可能产生多个解,需要根据经济意义筛选:
mathematica复制Select[retailerSolution,
And @@ {
(p1 /. #) > 0,
(p2 /. #) > 0,
(q1 /. #) > 0,
(q2 /. #) > 0
} &]
5.3 数值稳定性技巧
- 使用Chop函数消除极小虚部
- 高精度计算时设置WorkingPrecision
- 参数代入顺序影响结果稳定性,建议最后代入关键参数
6. 模型扩展与实践建议
6.1 现实场景调整
实际应用中可能需要考虑:
- 运输成本差异:为不同零售商设置不同的cr
- 需求波动:将a1,a2设为随机变量
- 契约设计:引入回购或收益共享条款
6.2 计算性能优化
对于大规模问题:
- 使用Compile生成编译函数
- 并行计算:Parallelize
- 记忆化:Memoization技术
6.3 结果验证方法
确保模型正确性的三种手段:
- 极限测试:令θ→0验证是否退化为独立市场
- 数值对比:与MATLAB/Python结果交叉验证
- 文献对照:与经典论文结果比对
我在实际复现中发现,当θ>0.5时模型可能出现负需求,这时需要引入非负约束重新求解。另外Mathematica的符号结果虽然精确,但有时需要手动化简才能得到简洁的经济学解释。建议重要结果都输出TeX格式便于论文撰写。
