SymPy求解复杂表达式耗时过长,寻求优化方案
SymPy符号求解性能优化问题
我正在用SymPy对下方方程做符号求解,已经在solve函数里设置了simplify=False和rational=False,这对eq7的求解帮助很大,但对eq14完全没用,求解耗时极久。同款代码在Matlab里只需要几秒就能完成,该怎么优化?
from sympy import symbols, Eq, solve, Function def dynamic_solver(): # Define symbolic variables C_steps, O, Kc, Ko, kc, ko, S, Q, CB6F, RUB, kq, Kp1, Kp2, Kd, Kf, Ku, nl, nc, JP700_j, JP700_c, a2, a1, Abs, phi2P_a, phi2p_a, phi2u_a, q2_a, JP680_j, Vc_j, An_j, Ag_j, An_c, Ag_c, E, gtc, gm, Ca, Vc_c, Rd = symbols( 'C_steps O Kc Ko kc ko S Q CB6F RUB kq Kp1 Kp2 Kd Kf Ku nl nc JP700_j JP700_c a2 a1 Abs phi2P_a phi2p_a phi2u_a q2_a JP680_j Vc_j An_j Ag_j An_c Ag_c E gtc gm Ca Vc_c Rd' ) # Calculate S and gammas S = (kc / Kc) * (Ko / ko) gammas = O / (2 * S) # Define equations eq1 = JP700_j - (Q * CB6F * kq) / (Q + (CB6F * kq) / ((Abs - a2) * (Kp1 / (Kp1 + Kd + Kf)))) eq2 = eq1.subs(JP700_j, JP680_j * (1 - (nl / nc) + (3 + 7 * gammas / C_steps) / ((4 + 8 * gammas / C_steps) * nc))) eq3 = eq2.subs(JP680_j, Vc_j * (4 * (1 + 2 * gammas / C_steps))) eq4 = eq3.subs(Vc_j, Ag_j / (1 - gammas / C_steps)) eq5 = eq4.subs(Ag_j, An_j + Rd) eq6 = eq5.subs(An_j, -(C_steps * E * gm + Ca * E * gm + 2 * C_steps * gm * gtc - 2 * Ca * gm * gtc) / (E + 2 * gm + 2 * gtc)) eq7 = solve(eq6, a2, dict=True,simplify=False,rational=False) # Pass out the first root eqA = Function('eqA')(Abs, C_steps, CB6F, Ca, E, Kc, Kd, Kf, Ko, Kp1, O, Q, Rd, gm, gtc, kc, ko, kq, nc, nl) eqA = eq7[0][a2] # Define equations for the second case eq8 = JP700_j - Q * a2 * phi2P_a * (1 - (nl / nc) + (3 + 7 * gammas / C_steps) / ((4 + 8 * gammas / C_steps) * nc)) eq9 = eq8.subs(JP700_j, Q * CB6F * kq / (Q + CB6F * kq / ((Abs - a2) * (Kp1 / (Kp1 + Kd + Kf))))) eq10 = eq9.subs(phi2P_a, phi2p_a / (1 - phi2u_a)) eq11 = eq10.subs(phi2p_a, (q2_a) * Kp2 / (Kp2 + Kd + Kf + Ku)) eq12 = eq11.subs(phi2u_a, (q2_a) * Ku / (Kp2 + Kd + Kf + Ku) + (1 - q2_a) * Ku / (Kd + Kf + Ku)) eq13 = eq12.subs(q2_a, 1 - (Q / (Q + CB6F * kq / ((Abs - a2) * (Kp1 / (Kp1 + Kd + Kf)))))) eq14 = solve(eq13, a2, dict=True,simplify=False,rational=False) # Pass out the second root eqB = Function('eqB')(Abs, C_steps, CB6F, Kc, Kd, Kf, Ko, Kp1, Kp2, Ku, O, Q, kc, ko, kq, nc, nl) eqB = eq14[1][a2] return eqA, eqB # Call the dynamic_solver function to obtain the equations eqA and eqB eqA, eqB = dynamic_solver()
优化建议
- 清理无关变量:代码中
RUB、JP700_c、a1、An_c、Ag_c、Vc_c这些变量完全没参与eq13的推导,删除它们可以直接减少SymPy的计算负载。 - 复用重复子表达式:多次出现的
Q + CB6F * kq / ((Abs - a2) * (Kp1 / (Kp1 + Kd + Kf)))可以定义为临时符号,比如:
后续所有用到该表达式的地方直接替换为temp_term = Q + CB6F * kq / ((Abs - a2) * (Kp1 / (Kp1 + Kd + Kf)))temp_term,避免重复构建复杂表达式。 - 分步化简中间式:在每一步
subs后对表达式做轻量化简(比如eq9 = eq9.simplify()),避免最终的eq13成为极度臃肿的分式结构,降低求解器的处理难度。 - 转化为多项式求解:对eq13先通分去掉分母,将其转化为多项式方程后再求解。可以用
eq13_poly = eq13.as_poly(a2),再对多项式调用solve,多项式求解通常比分式方程更高效。 - 切换求解器:尝试用
solveset替代solve,或者指定求解器的方法,比如对于有理方程,启用rational=True(根据方程实际情况调整),部分场景下专用求解逻辑会比通用求解器更快。
内容的提问来源于stack exchange,提问作者Ress
相关产品推荐
相关产品推荐

