1. 项目背景与核心问题
供应链管理中的供应商-零售商模型是运筹学领域的经典研究课题。这个双零售商单供应商模型(1S2R)主要探讨在单一供应商服务两个独立零售商场景下的库存优化、定价策略和利润分配问题。我在复现这篇论文时发现,虽然模型结构看似简单,但涉及非线性约束条件和多变量优化,手动计算几乎不可能完成,这正是Mathematica这类符号计算软件大显身手的地方。
2. 模型构建与数学表达
2.1 基础模型框架
该模型包含三个决策主体:
- 供应商:决定批发价格w和生产量Q
- 零售商1和2:分别决定订购量q₁和q₂
- 市场需求函数:Dᵢ(pᵢ) = aᵢ - bᵢpᵢ (i=1,2)
利润函数构成:
mathematica复制π_supplier = (w - c)Q - K I{Q>0}
π_retailer1 = (p1 - w)q1
π_retailer2 = (p2 - w)q2
其中c是单位生产成本,K是固定启动成本,I是指示函数。
2.2 约束条件处理
模型需要处理的关键约束:
- 供需平衡:Q = q₁ + q₂
- 非负约束:所有变量 ≥ 0
- 市场需求限制:qᵢ ≤ Dᵢ(pᵢ)
在Mathematica中,我们用Reduce函数处理这些约束:
mathematica复制constraints = {
Q == q1 + q2,
q1 <= a1 - b1*p1,
q2 <= a2 - b2*p2,
{Q, q1, q2, w, p1, p2} >= 0
};
3. Mathematica求解实现
3.1 参数化建模
首先定义符号变量和参数:
mathematica复制vars = {Q, q1, q2, w, p1, p2};
params = {a1 -> 100, a2 -> 80, b1 -> 2, b2 -> 1.5, c -> 10, K -> 200};
3.2 利润最大化求解
使用Maximize函数进行全局优化:
mathematica复制solution = Maximize[
{
(w - c)Q - K Boole[Q > 0] + (p1 - w)q1 + (p2 - w)q2,
constraints
},
vars
] //. params // N
3.3 结果可视化
生成价格-需求关系图:
mathematica复制Plot3D[
{q1 /. solution[[2]], q2 /. solution[[2]]},
{p1, 20, 50}, {p2, 30, 60},
AxesLabel -> {"p1", "p2", "Quantity"},
PlotStyle -> {Blue, Orange}
]
4. 关键技术与难点突破
4.1 非连续成本处理
固定成本K导致利润函数不连续,传统优化方法失效。Mathematica的Boole函数完美解决了这个问题:
mathematica复制discreteCost = K Boole[Q > 0];
4.2 多极值点问题
模型可能存在多个局部最优解。我们采用以下策略确保找到全局最优:
- 使用RandomSearch方法进行初步探索
- 结合NMaximize的多种算法("DifferentialEvolution"、"SimulatedAnnealing")
- 验证KKT条件
mathematica复制methods = {
"RandomSearch",
{"DifferentialEvolution", "SearchPoints" -> 50},
"SimulatedAnnealing"
};
Table[
NMaximize[profit, vars, Method -> method],
{method, methods}
]
5. 完整实现代码
mathematica复制(* 模型初始化 *)
ClearAll["Global`*"];
vars = {Q, q1, q2, w, p1, p2};
params = {a1 -> 100, a2 -> 80, b1 -> 2, b2 -> 1.5, c -> 10, K -> 200};
(* 约束条件 *)
constraints = {
Q == q1 + q2,
q1 <= a1 - b1*p1,
q2 <= a2 - b2*p2,
Thread[vars >= 0]
};
(* 利润函数 *)
profit = (w - c)Q - K Boole[Q > 0] + (p1 - w)q1 + (p2 - w)q2;
(* 求解过程 *)
solution = Maximize[
{profit, constraints} //. params,
vars
] // N;
(* 结果输出 *)
Print["Optimal Solution:"];
Print[solution];
(* 灵敏度分析 *)
SensitivityAnalysis[vars_, params_, profit_] := Module[
{base, perturbations, results},
base = Last@Maximize[{profit, constraints} //. params, vars] // N;
results = Table[
newParams = MapAt[#*1.01 &, params, i];
newSol = Last@Maximize[{profit, constraints} //. newParams, vars] // N;
(newSol - base)/base,
{i, Length[params]}
];
BarChart[results*100,
ChartLabels -> Keys[params],
AxesLabel -> {"Parameter", "Profit Change (%)"}]
];
SensitivityAnalysis[vars, params, profit];
6. 实际应用中的经验技巧
6.1 参数敏感性处理
通过Manipulate函数创建交互式分析界面:
mathematica复制Manipulate[
params = {a1 -> a1val, a2 -> a2val, b1 -> b1val, b2 -> b2val, c -> cval, K -> Kval};
sol = Maximize[{profit, constraints} //. params, vars] // N;
Column[{
Plot[
{a1 - b1*p1, a2 - b2*p2} /. params,
{p1, 0, 50}, PlotRange -> All,
AxesLabel -> {"Price", "Demand"},
PlotLegends -> {"Retailer 1", "Retailer 2"}
],
Grid[{
{"Wholesale Price", w /. sol[[2]]},
{"Total Production", Q /. sol[[2]]},
{"Retailer 1 Order", q1 /. sol[[2]]},
{"Retailer 2 Order", q2 /. sol[[2]]}
}, Frame -> All]
}],
{{a1val, 100}, 50, 150}, {{a2val, 80}, 40, 120},
{{b1val, 2}, 1, 3}, {{b2val, 1.5}, 0.5, 2.5},
{{cval, 10}, 5, 15}, {{Kval, 200}, 100, 300}
]
6.2 计算性能优化
对于大规模问题,采用以下加速策略:
- 提前数值化参数
- 使用Compile生成C代码
- 并行计算不同场景
mathematica复制compiledProfit = Compile[
{{Q, _Real}, {q1, _Real}, {q2, _Real}, {w, _Real}, {p1, _Real}, {p2, _Real}},
(w - 10)*Q - 200*If[Q > 0, 1, 0] + (p1 - w)*q1 + (p2 - w)*q2,
CompilationTarget -> "C"
];
ParallelTable[
NMaximize[
compiledProfit[Q, q1, q2, w, p1, p2],
constraints,
Method -> "DifferentialEvolution"
],
{a1val, 90, 110, 5}
]
7. 模型扩展与变体
7.1 竞争模式变体
考虑零售商之间的价格竞争时,需求函数变为:
mathematica复制D1 = a1 - b1*p1 + d*p2
D2 = a2 - b2*p2 + d*p1
对应的纳什均衡求解:
mathematica复制nashSolution = FindInstance[
{
D[p1*(a1 - b1*p1 + d*p2) - w*(a1 - b1*p1 + d*p2), p1] == 0,
D[p2*(a2 - b2*p2 + d*p1) - w*(a2 - b2*p2 + d*p1), p2] == 0
},
{p1, p2}
]
7.2 随机需求模型
当需求具有随机性时,采用蒙特卡洛模拟:
mathematica复制simulations = Table[
randDemand1 = Max[0, a1 - b1*p1 + RandomVariate[NormalDistribution[0, 5]]];
randDemand2 = Max[0, a2 - b2*p2 + RandomVariate[NormalDistribution[0, 5]]];
{p1, p2, w, randDemand1, randDemand2},
{10000}
];
Histogram3D[
simulations[[All, {4, 5}]],
AxesLabel -> {"Demand1", "Demand2", "Frequency"}
]
