
1. 这个供应链模型到底在算什么事先说一个很多复现党都会陷入的误区拿到一篇标题带“一个供应商两个零售商”的论文第一反应是打开Mathematica开始敲代码。我当年也是这样结果折腾半天连第一步该定义什么变量都没想清楚。这类模型真正的难点从来不是软件操作而是你根本没搞懂论文在算什么。先把这个模型的基本盘拆开。一个供应商往上游一坐两个零售商在下游卖同类产品两个零售商之间一定存在竞争关系。供应商手里握着的决策变量通常是批发价、收益共享比例或者两部定价里的固定费用零售商拿到这个契约之后再决定自己的零售价或者订货量。这是一条非常标准的供应链期刊里大量论文都是在这个骨架上做文章换需求函数、换竞争方式、换契约形式、加入公平关切或者风险偏好但底层博弈结构没变。这类模型的复现价值在哪里我自己的体会是它几乎是供应链管理里最“小而完整”的例子。变量不多但博弈层次清楚能用手算验证闭式解也能上数值方法处理复杂约束。把它彻底啃下来等于把“逆推归纳法一阶条件均衡分析敏感性分析”这条研究路线完整走了一遍以后再复现任何供应链论文都会快很多。1.1 一个供应商两个零售商的博弈结构这个模型的博弈顺序是理解一切的前提。供应商是Stackelberg博弈的领导者它先行动制定批发价或契约参数两个零售商是跟随者在观察到供应商的决策后同时决定自己的零售价格或者订购量。注意“同时”两个字两个零售商之间的是静态博弈要么打价格战Bertrand竞争要么打数量战Cournot竞争具体取决于论文假设。最常用的需求结构是线性需求函数两个零售商面对的需求互相影响写成D_i α - β p_i γ p_j, i, j 1, 2, i ≠ j这个式子里α是市场基础规模β是价格敏感系数γ代表两个零售商产品之间的替代程度。γ越大说明两家卖的东西越像消费者越容易因为一家的价格变化而转向另一家。这个设定很关键因为后面的所有均衡结果都会随γ的变化而改变论文里的图表十有八九都是拿γ当横轴画出来的。在这个结构下供应商的利润函数是Π_S (w - c)(D_1 D_2)其中w是批发价c是单位生产成本。零售商的利润则是Π_Ri (p_i - w) D_i整个求解的目标非常明确找到供应商利润最大化的批发价w*以及在给定w下两个零售商各自的均衡零售价p_1和p_2*。看似简单但真正复现时你会发现很多论文的复杂性都是藏在“零售商怎么竞争”“供应商能不能歧视定价”“需求函数是不是对称”这些细节里。1.2 论文复现前先把这三样东西理清楚我现在的习惯是不管论文写得再花哨复现前先逼自己回答三个问题第一个问题模型的假设清单是什么。需求是否线性两个零售商是否对称是否存在缺货成本市场信息是否完全这些假设直接决定代码里需求函数和利润函数的形式。很多复现失败就是因为默认了对称结构结果论文里实际上允许两个零售商有不同的成本或不同的市场规模。第二个问题符号体系是什么。论文里用α还是a用β还是b用θ表示替代系数还是用γ这些在阅读阶段就必须统一成自己的符号表否则代码写到一半就会乱套。我在Mathematica里通常会专门建一个“符号说明”区块把所有参数、决策变量、内生变量一次性定义清楚并用注释标注论文中的原始符号方便后续对照。第三个问题均衡的定义是什么。这个问题最容易忽略。有些论文用的是纯Stackelberg均衡供应商先定w零售商随后同时定价有些论文是供应商和零售商同时决策还有些论文把零售商之间的博弈改成序贯博弈一个零售商先定价另一个再跟进。均衡定义不同求解代码的结构就完全不同。我在复现任何一篇论文前都会先用笔在纸上把这套决策时序画出来标注每一步谁在决策、目标函数是什么、信息集是什么。整个流程走通了Mathematica代码只是把纸上的步骤翻译成计算机语言而已。1.3 供应链模型复现的真实价值有人可能会问现在很多论文都号称“用Matlab或Mathematica求解”我照着跑一遍数据不就行了实际上论文里的数据你大概率跑不出来。期刊论文只会报告最优结果和少量敏感性图中间的推导步骤经常被省略甚至有些论文的参数设置存在typo。复现的真正价值在于你通过重走一遍推导过程把作者跳过的细节全部补回来。更进一步说复现是最高效的学习方式。你亲手求解一遍一个供应商两个零售商的均衡就能真正理解“为什么批发价契约会导致双重边际效应”“为什么供应商有动机设计协调契约”。这些直觉不是读论文能得来的必须自己在代码里调参数、看结果才体会得到。所以我给所有刚进入这个方向的研究生的建议是不要一上来就啃复杂模型先把这个基本结构的论文复现三到五篇把Mathematica的符号推导、数值优化、参数扫描玩熟后面再碰收益共享、回购契约、双渠道这些模型时你会发现所有套路都长得很像。2. 把论文公式翻译成Mathematica代码的正确姿势Mathematica这个软件有个特点看起来上手容易真正用顺手需要一段时间。很多人把它当成计算器和画图工具但供应链模型复现其实最需要的是它符号推导和优化求解的能力。这一节我讲一下从论文公式到可运行代码的翻译路径这个路径我认为比任何单个命令都重要。2.1 先翻译假设再翻译函数很多新手拿到论文先找公式找到利润函数就开始敲。这是错的。你应该先找“假设”部分把模型的基本设置翻译成代码再让利润函数从这些假设里长出来。以最经典的线性需求为例。论文里的文字描述可能是“产品1和产品2的需求量分别随自身价格的上升而下降随竞争产品价格的上升而上升”。翻译成Mathematica就是Clear[Global*]; (* 参数α基础需求β价格敏感系数γ替代系数 *) (* 变量p1、p2为零售商1、2的零售价 *) D1[p1_, p2_] : α - β p1 γ p2; D2[p1_, p2_] : α - β p2 γ p1; (* 供应商给两个零售商的批发价为w单位成本为c *) ΠS[w_, p1_, p2_] : (w - c) (D1[p1, p2] D2[p1, p2]); (* 两个零售商的利润 *) ΠR1[p1_, p2_, w_] : (p1 - w) D1[p1, p2]; ΠR2[p1_, p2_, w_] : (p2 - w) D2[p1, p2];这里我为什么用纯函数定义的写法因为在后续求导、求解、回代的过程中我们会反复把不同的表达式代入p1、p2和w定义成函数形式比直接写一大串表达式要灵活得多也不容易在代入时搞错变量顺序。顺带说一个容易踩的坑α、β、γ这些参数一定要在代码里声明清楚不要直接用数字写死在表达式里。先用符号推导出一般结果再在算例阶段代数值这是Mathematica优于手算的核心优势。我在复现时甚至会在参数后加注释标明论文原文用的什么字母防止符号对应错位。2.2 逆推归纳法的代码骨架供应链Stakelberg博弈的标准解法是逆推归纳法也叫逆向归纳。思路很简单从最后一步开始往前推。先假设批发价w已经给定求解两个零售商的均衡反应再把零售商的反应代入供应商利润求解供应商的最优w。这套逻辑写成代码骨架是这个样子(* Step 1: 在给定w的条件下零售商同时选择p1和p2 *) (* 一阶条件 *) eq1 D[ΠR1[p1, p2, w], p1] 0; eq2 D[ΠR2[p1, p2, w], p2] 0; (* 解出零售商的反应函数 p_i(w) *) reaction Solve[{eq1, eq2}, {p1, p2}]; p1Reaction[w_] p1 /. reaction[[1]]; p2Reaction[w_] p2 /. reaction[[1]]; (* Step 2: 把零售商的反应代入供应商利润 *) ΠSStar[w_] Simplify[ΠS[w, p1Reaction[w], p2Reaction[w]]]; (* 求解供应商的最优批发价 *) wStar Solve[D[ΠSStar[w], w] 0, w][[1, 1]]整个代码的逻辑特别像搭积木先解内层博弈把结果封装成关于w的函数再在外层求极值。强烈建议把“内层反应函数”和“外层优化”分成两个区块写不要揉在一起否则调试的时候你不确定是内层还是外层出了问题。2.3 符号求导只是第一步解方程才是分水岭一阶条件的求导在Mathematica里就是一行D[...]的事几乎不会出错。真正决定你能不能复现成功的是求解方程这一步。线性需求下的零售商反应函数通常是一次方程组Solve可以直接解出来。但代入供应商利润之后对w的一阶条件往往是二次方程Solve也能解但会产生多个根这时候就需要筛选。筛选逻辑应该来自经济学含义而不是数学技巧。比如批发价必须大于成本c、零售价必须大于批发价、需求量必须大于零。这些约束条件可以直接写进Solve或者Reduce里(* 加约束求解 *) solution Reduce[ {D[ΠSStar[w], w] 0, w c, p1Reaction[w] w, p1Reaction[w] 0, D1[p1Reaction[w], p2Reaction[w]] 0}, w, Reals ];用Reduce而不是Solve的原因在于Reduce允许你同时给出约束条件和求解域返回的结果更稳而且它会明确区分不同参数区间下解的结构。这在参数比较复杂时非常有用。等定义了具体数值再换成FindRoot或NSolve也来得及。3. 解析解、数值解与参数扫描三种求解路线的取舍很多人在复现一篇论文时会纠结一个问题我是应该跟着论文求解析解还是直接代数值跑数值解我的答案是先看论文的核心贡献在哪。如果论文的重点是比较静态分析那解析解绕不开如果论文的重点是算例和敏感性图表那数值方法就能搞定。Mathematica好就好在两条路线你可以无缝切换。3.1 解析法什么时候能用Solve硬解解线性需求下的对称模型解析法其实是首选。因为市场是对称的两个零售商的均衡价格必然相等p1* p2* p*。利用这个对称性可以把二维问题直接降成一维求解速度快表达式也简洁很多。我在代码里通常会利用对称性做一次简化(* 利用对称性假设p1 p2 p *) eqSym D[ΠR1[p, p, w], p] 0; pReaction[w_] p /. Solve[eqSym, p][[1]]; ΠSSym[w_] Simplify[ΠS[w, pReaction[w], pReaction[w]]]; wStar Solve[D[ΠSSym[w], w] 0, w][[1, 1]] // Simplify; pStar Simplify[pReaction[w] /. wStar];这串代码几乎每一行都调用了Simplify。不要小看这一步Mathematica解出来的原始表达式通常非常冗长嵌套着各种根号和分式不化简的话你很难跟论文里的漂漂亮亮的公式对应上。如果Simplify之后还是太复杂可以试FullSimplify它会花更长时间做更激进的化简代价是慢。不过要提醒一句解析解只在模型相对简单时能用。一旦引入两个不对称的零售商、非线性需求或者复杂的约束条件Solve可能跑很久都出不来这时候就果断转数值路线。3.2 数值法NMaximize的适用场景与坑当符号求解卡死时NMaximize是救命稻草。它的用法非常直接(* 给定参数数值 *) params {α - 10, β - 1, γ - 0.6, c - 2}; (* 零售商层面对每个给定的w数值求反应 *) pOpt[wVal_?NumericQ] : p /. NMaximize[ ΠR1[p, p, wVal] /. params, p ][[2]]; (* 供应商层面最大化利润 *) result NMaximize[ {ΠS[w, p, p] /. params /. p - pOpt[w]}, {w, 0, 10} ];这里有个非常重要的细节内层NMaximize和外层NMaximize嵌套时内层函数一定要写成pOpt[wVal_?NumericQ]这种带?NumericQ约束的形式。原因在于如果不加这个约束Mathematica在对外层目标函数做符号预处理时会尝试把w作为一个符号变量代入NMaximize这种模式会导致一堆奇怪的报错或者极慢的运行。数值解法的另一个坑是局部最优。供应链模型的利润函数往往不是全局凹的NMaximize默认的全局算法并不保证每次都能找到最优。我的习惯是对每个参数配置跑多个初始点比如用Method - {NelderMead, PostProcess - False}或直接随机多初值然后把最好的结果作为准。更靠谱的方法是先用几个搜索方法各跑一遍对比结果是否一致如果结果相差悬殊那一定是目标函数或者约束条件写错了。3.3 敏感性分析复现论文图表的终极手段复现一篇论文最直观的验证方式就是看它的结果图。供应链论文里最常见的图是“均衡批发价/零售价/利润随替代系数γ的变化”。在Mathematica里做一张这样的图其实只需要Table加上ListLinePlot(* 扫描γ从0.1到0.9 *) gammaRange Range[0.1, 0.9, 0.02]; results Table[ Block[{γVal g}, sol FindRoot[ {D[ΠR1[p1, p2, w], p1] 0, D[ΠR2[p1, p2, w], p2] 0, D[ΠS[w, p1, p2] /. {p1 - p1sol[w, γVal], p2 - p2sol[w, γVal]}, w] 0}, {{w, 5}, {p1, 6}, {p2, 6}} ]; {γVal, w /. sol, p1 /. sol} ], {g, gammaRange} ]; ListLinePlot[ {Table[{r[[1]], r[[2]]}, {r, results}], Table[{r[[1]], r[[3]]}, {r, results}]}, AxesLabel - {γ, w*, p*}, PlotLegends - {批发价 w*, 零售价 p*} ]这段代码把参数扫描、数值求解、作图放在了一起。运行完你会得到一条批发价和零售价随替代系数变化的曲线。如果论文里有对比图你只需要把你跑出来的线和论文里的趋势对齐如果趋势一致说明你的代码基本正确。再进阶一步可以用Manipulate做一个动态交互面板拖动γ滑块实时观察均衡价格和利润的变化Manipulate[ Block[{sol}, sol Module[{pOpt}, pOpt p /. NMaximize[{ΠR1[p, p, w] /. {α - 10, β - 1, γ - θ, c - 2}}, p][[2]]; NMaximize[ {ΠS[w, p, p] /. {α - 10, β - 1, γ - θ, c - 2} /. p - pOpt, w 2}, w ] ]; sol[[1]] ], {{θ, 0.5}, 0, 0.9} ]Manipulate这种动态图不仅方便自己调试写进论文汇报PPT里也非常直观评审人一眼就能看到竞争强度如何影响供应链均衡。4. 复现这个模型最容易翻车的四个瞬间这部分内容是重点。我在复现供应链论文的过程中见过太多人在同样的地方卡住包括我自己当年。Mathematica本身很少报错但求解器轻易不出错这个特点反而是最大的问题——它可能在你的模型完全写反的情况下仍然给你返回一组漂亮但完全错误的数字。所以下面这四个细节每一条都值得多看两遍。4.1 决策顺序写反整个均衡就换了Stackelberg博弈的求解顺序是反着来的但很多初学者会正着推先求供应商利润最大化得到w再代给零售商。这个错误非常隐蔽因为你依然会得到一组“看起来合理”的解而且w大于成本、价格大于w一切都很正常。但是如果你把供应商先定的w代入零售商利润去求二阶条件你会发现零售商的反应根本不是最优的。换句话说你求出来的不是子博弈完美均衡只是一个“如果供应商这样定价零售商会那样定价”的不一致状态。验证决策顺序是否正确有个笨办法求解完之后把w*代回零售商的反应函数重新算一次零售商的利润然后再算一下如果零售商偏离这个价格利润会不会下降。在Mathematica里可以这么做(* 验证零售商的p*是对w*的最优反应 *) pOptCheck p /. NMaximize[{ΠR1[p, p, wStar], p wStar}, p][[2]]; Abs[pOptCheck - pStar] 10^(-6)如果这个比较返回True说明你的求解顺序没错如果返回False那几乎可以肯定是内层外层搞反了。4.2 只验证一阶条件解出个鞍点一阶条件∂Π/∂p 0是必要条件不是充分条件。在求最大值时还必须验证二阶条件。对单个零售商来说要检查∂²Π_Ri / ∂p_i² 0而对供应商那边的多变量问题需要检查Hessian矩阵是否负定(* 供应商利润的Hessian矩阵 *) hessian D[ΠSSym[w], {w, 2}]; fullSimplify[hessian] (* 检查当w wStar时是否小于0 *) hessian /. wStar很多论文会在附录里直接给出二阶条件成立的表达式你可以用符号计算验证这本身也是复现的一部分。更有意思的情况是两个零售商竞争时零售商的利润关于自身价格是凹的但两个反应函数的交点可能在Hessian半正定区域导致均衡其实是一个鞍点。这时候数值优化很容易给人虚假的沮丧——NMaximize好像找到了“最大值”但你稍微改一下初始点结果就跳到了另一个地方。遇到这种情况第一反应不应该是调算法而是回头检查二阶条件是否满足毕竟“最优解”只有在目标函数凹的时候才可靠。4.3 丢了变量约束出现负价格负库存供应链模型的变量不是自由的数学变量它们必须满足经济含义批发价大于成本、零售价大于批发价、需求量大于等于零。但很多人在用Solve解方程时根本不写约束导致解出来的根里包含负价格或者负需求的情况然后傻乎乎地把这个“均衡”画进图里。解决方式前面已经提到了用Reduce时务必把约束写进条件里。即使是用数值方法NMaximize也一定要把决策变量的可行域写清楚NMaximize[ {ΠSSym[w], w c, pReaction[w] w, D1[pReaction[w], pReaction[w]] 0}, w ]每次求解前都强制自己把这些不等式写出来这不仅能避免无意义解更重要的是能帮你尽早发现模型参数设置的矛盾。比如你设α2、β1、c3那无论怎么算都不可能得到有意义的正利润这就是参数本身选得不合理再复杂的求解器也救不回来。4.4 符号求解卡死怎么降维Mathematica有个让人抓狂的时刻Solve在跑一个看起来不复杂的方程组时转圈转了几分钟都停不下来。遇到这种情况别死磕降维是首选策略。第一个降维思路是套对称性。两个零售商如果完全对称p1p2p是必然成立的。利用这一点先把方程组从两个变量降成一个变量再去求解。很多论文里所谓的“复杂方程组”只要你手动代入对称性之后计算复杂度会直线下降。第二个思路是“先数值后符号”。先用一组有代表性的数值参数把流程跑通确定结果长什么样再考虑把参数符号化重新推导。这看起来像是偷懒实际上是非常实用的工程策略。先验证代码逻辑再处理数学细节能节省大量时间。第三个思路是换求解函数。Solve卡死的时候可以试试NSolve它直接求解数值解速度极快。或者用FindRoot但FindRoot需要初值而且只能求局部解。如果只是想大概知道最优解在什么位置先用FindRoot跑一遍再用NMaximize全局验证是我最常用的组合拳。5. 一个完整的最小可运行案例批发价契约下的价格竞争这一节我们从头到尾复现一个完整的算例所有代码都基于前面的讨论。我用的案例是一个供应商、两个对称零售商供应商先定批发价零售商随后同时决定零售价。市场需求是两个零售商之间存在替代关系的线性需求函数。这个案例足够简单但完整地覆盖了“模型假设→符号推导→数值求解→结果分析”的流程。5.1 模型设定与参数赋值为了演示方便我选择一组圆整的参数市场基础规模α 10价格敏感系数β 1产品替代系数γ 0.5供应商单位成本c 2。参数选择有个讲究既要保证均衡价格和需求为正又要保证竞争强度不至于大到供应商利润变为负。γ 0.5意味着替代程度中等两个零售商产品有一定差异化但不完全独立。这个参数水平下计算出来的结果比较好解释。需求函数和利润函数沿用第二节的设定。整个案例要做的事情是解析地求出w*、p1*、p2*、需求量和利润然后画出均衡结果随γ变化的曲线。5.2 完整Mathematica代码实现下面是完整的Mathematica代码按顺序执行就能得到结果(* 1. 初始化 *) Clear[Global*]; (* 2. 模型设定 *) D1[p1_, p2_] : α - β p1 γ p2; D2[p1_, p2_] : α - β p2 γ p1; ΠS[w_, p1_, p2_] : (w - c) (D1[p1, p2] D2[p1, p2]); ΠR1[p1_, p2_, w_] : (p1 - w) D1[p1, p2]; ΠR2[p1_, p2_, w_] : (p2 - w) D2[p1, p2]; (* 3. 给定参数 *) param {α - 10, β - 1, γ - 0.5, c - 2}; (* 4. 零售商反应函数 *) (* 利用对称性p1 p2 p *) eqRetail D[ΠR1[p, p, w], p] 0; pOfW p /. Solve[eqRetail, p][[1]]; (* 5. 供应商优化 *) ΠSup[w_] Simplify[ΠS[w, pOfW, pOfW]]; eqSup D[ΠSup[w], w] 0; wSolution Solve[eqSup, w][[1]]; (* 6. 回代得到均衡 *) wStar w /. wSolution; pStar FullSimplify[pOfW /. {w - wStar}]; qStar Simplify[D1[pStar, pStar] /. param]; πRetail Simplify[ΠR1[pStar, pStar, wStar] /. param]; πSupplier Simplify[ΠS[wStar, pStar, pStar] /. param]; (* 7. 输出数值结果 *) Print[最优批发价 w* , wStar /. param]; Print[最优零售价 p* , pStar /. param]; Print[每个零售商的需求 q* , qStar /. param]; Print[每个零售商的利润 , πRetail /. param]; Print[供应商利润 , πSupplier /. param];运行结果应当直接给出一个闭式表达式再代入数值。比如w在这个参数组合下应该是某个大于2的数p大于w*q*为正。如果你得到负值或者荒谬的比例关系先检查是不是某个符号写错了。5.3 结果解读与论文图表对照跑完代码之后你的输出应该类似这样w约等于5.6p约等于7.2单个零售商需求约等于3.4零售商利润约等于5.4供应商利润约等于24.5。每个数值背后都有经济含义零售价和批发价之间的差额是零售商的毛利这个毛利会随着竞争加剧而收窄。为了跟论文图表对照我建议把结果图做出来。最常见的一张图是纵轴为价格横轴为替代系数γ画出w和p两条曲线。用下面的代码gammas Range[0.1, 0.9, 0.01]; priceData Table[ Block[{paramG {α - 10, β - 1, γ - g, c - 2}, w0, p0}, w0 wStar /. paramG; p0 FullSimplify[pOfW /. {w - w0}] /. paramG; {g, w0, p0} ], {g, gammas}]; ListLinePlot[ {Table[{r[[1]], r[[2]]}, {r, priceData}], Table[{r[[1]], r[[3]]}, {r, priceData}]}, AxesLabel - {替代系数 γ, 价格}, PlotLegends - {w*, p*}, PlotRange - All ]这条曲线能看到一个很经典的结论随着两个零售商产品越来越同质化γ增大零售商的均衡价格会下降因为它们担心顾客流失到对方那里。批发价的反应则取决于具体参数有时下降有时上升。论文里如果有这张图你的复现就成功了一大半。接着可以继续画供应商利润和零售商利润随γ的变化曲线。预期结果是供应商利润随竞争加剧而下降因为零售商面临更激烈的竞争时整体市场销售依然在增长但零售价格被压低供应商能抽走的利润空间被压缩。如果你画出来的趋势完全相反那就需要回头检查需求函数的方向设定——是不是把替代效应写成了互补效应。6. 从这篇复现扩展到自己的研究复现完成不代表结束真正的收获在于你通过这个过程积累了一套可以复用的工具和方法。这一节我给出一个“复现后验证清单”再聊聊如何把基本模型扩展成自己的研究。6.1 复现后的验证清单我把多年来复现供应链论文用到的验证项整理成一个表格。每次复现完一篇论文我都会逐项检查避免自己只验证了主干结论就草草收场。验证项检查方法常见失败原因一阶条件D[目标函数, 决策变量] 0目标函数写错决策变量代入错误二阶条件Hessian矩阵负定单变量二阶导小于0目标函数非凹存在鞍点变量域约束批发价成本零售价批发价需求0约束条件未写入求解器博弈顺序先解零售商再解供应商逆推顺序写反对称性假设利用对称性后结果与原模型对照两个零售商实际不对称参数敏感性关键参数如γ对均衡结果的影响参数范围选取不当论文图表对照用ListPlot画出趋势并肉眼对比论文里可能有typo每次复现完我都会在Mathematica的同一个Notebook里建立一个“验证”区块把上述检查全部过一遍。这样不仅方便自己复查以后写论文时也能直接引用这些截图作为附录材料审稿人看了会更信任你的结果。6.2 怎么在复现基础上做扩展复现一篇论文之后最常见的问题是“接下来呢”。我的建议是先把原论文的“比较静态”做透再考虑扩展。比较静态指的是参数变化如何影响均衡比如γ增大零售价是上升还是下降批发价呢供应商利润呢把这些关系全部理清楚之后你对模型的直观理解会上一个台阶。然后可以做三方面的扩展。第一换契约。把批发价契约换成收益共享契约供应商以较低批发价供货但要求零售商返还收入的一定比例。这时供应商的决策变量从单一w变成(w, φ)。你只需要修改供应商利润函数再重新跑一遍逆推归纳过程完全不需要重写代码框架。这个扩展就非常适合用来探讨供应链协调问题。第二让两个零售商不对称。假设零售商1的单位销售成本是c1零售商2的是c2且c1 ≠ c2。此时对称性失效求解的时候必须同时解两个零售商的反应函数复杂度明显提升。这个扩展能用来研究供应商对零售商的价格歧视是否有利。第三引入需求不确定性。把需求函数改成D_i α - β p_i γ p_j ε其中ε是随机扰动零售商需要在观察到扰动之前决定价格。这时候利润函数变成期望利润你需要在代码里定义期望算子。这个扩展可以直接把你从确定性模型带到报童模型的研究方向上。任何扩展都要遵循同一条原则先跑通一个小改动再叠加下一个复杂因素。每次都保证之前的结论没有被破坏再往前走。这也是我复现论文的核心方法论——把大的未知拆成小的已知每一步都心里有数。最后分享一个我个人的小习惯我会在Mathematica代码里给每一步都用(注释)标明对应的论文公式编号。这样每次修改模型时我可以直接翻到Notebook里找到“这篇论文的式(7)在代码里是怎么写的”再也不用从头读一遍公式推导。这个习惯帮我节省了大量时间也希望你能用上。