SymPy求解斯塔克尔伯格博弈方程组无法整理结果求助
问题分析与修正方案
1. 现有代码的核心问题
- IndexedBase代码:SymPy未自动简化
Sum(KroneckerDelta(j,k), (k,1,3))(该求和结果为1,仅当k=j时KroneckerDelta为1,其余为0),且未引入总和符号简化方程,导致结果保留冗余求和项。 - 独立符号代码:错误将变量
a,b,c定义为Idx类型(Idx是索引符号,仅用于标记IndexedBase的下标,不能作为普通运算变量),导致求导和求解逻辑异常,返回空解。
2. 正确求解思路
由于斯塔克尔伯格博弈中n个玩家对称,最优解必然满足所有x[j]相等,可利用这一对称性减少变量数量,先求解总和S = x₁+x₂+x₃,再推导单个x[j]的表达式。
3. 修正后的代码实现
方法1:使用普通符号+对称性简化
from sympy import * # 定义普通运算符号,避免与Idx混淆 a, b, c = symbols('a b c') R, c_const = symbols('R c') # 常量c与变量名区分开 # 定义总和S S = a + b + c # 写出偏导后的方程(对应原函数f_j = (R·x_j)/S - c·x_j的偏导结果) eq1 = R/S - R*a/S**2 - c_const eq2 = R/S - R*b/S**2 - c_const eq3 = R/S - R*c/S**2 - c_const # 利用对称性:从eq1=eq2可得a=b,eq2=eq3可得b=c,设a=b=c=t t = symbols('t') subs_map = {a: t, b: t, c: t, S: 3*t} # 代入方程求解t eq_sub = eq1.subs(subs_map) t_solutions = solve(eq_sub, t) # 过滤零解,得到非零最优解 non_zero_sol = [sol for sol in t_solutions if sol != 0][0] final_sol = {a: non_zero_sol, b: non_zero_sol, c: non_zero_sol} print("最优解:", final_sol)
方法2:使用IndexedBase+手动简化
from sympy import * real_n = 3 x = IndexedBase('x') j, k = symbols('j k', cls=Idx) R, c = symbols('R c') # 定义总和S S = Sum(x[k], (k, 1, real_n)) # 原函数f_j f = R * x[j]/S - c * x[j] # 求偏导并手动简化KroneckerDelta求和项(结果为1) equ = diff(f, x[j]) equ_simplified = equ.subs(Sum(KroneckerDelta(j, k), (k, 1, real_n)), 1) # 生成三个方程 eqs = [equ_simplified.subs(j, i) for i in range(1, real_n+1)] # 利用对称性设所有x[j]相等为t,总和S=3t t = symbols('t') subs_dict = {x[i]: t for i in range(1, real_n+1)} subs_dict[S] = 3*t # 代入求解 eq_substituted = eqs[0].subs(subs_dict) t_sol = solve(eq_substituted, t) # 输出非零解 x_sol = {x[i]: t_sol[1] for i in range(1, real_n+1)} print("最优解:", x_sol)
4. 关键建议
- 永远不要将普通运算变量定义为
Idx类型,Idx仅用于标记IndexedBase的下标。 - 对称博弈问题优先利用对称性减少变量,大幅降低求解复杂度,避免SymPy处理冗余方程。
- 对于SymPy未自动简化的特殊项(如KroneckerDelta求和),手动代入简化结果后再求解。
内容的提问来源于stack exchange,提问作者vio1etus
相关产品推荐
相关产品推荐

