如何用Sympy合并多个lambdify生成的函数?
解决方案
1. 手动构建完整符号表达式(避开CSE自动优化的bug)
既然手动拆分辅助函数可行,说明中间步骤的符号表达式是正确的。可以将这些中间符号结果手动代入最终的加速度表达式,生成完整的符号函数后再进行lambdify:
import sympy as sp # 定义原变量 t, x, y, z = sp.symbols('t x y z') # 第一步变换:定义中间符号表达式T1(替换为你的实际变换逻辑) T1_x = sp.cos(t)*x - sp.sin(t)*y T1_y = sp.sin(t)*x + sp.cos(t)*y T1_z = z # 第二步变换:基于T1的结果定义T2(替换为你的实际变换逻辑) T2_x = T1_x + sp.sin(t)*T1_z T2_y = T1_y - sp.cos(t)*T1_z T2_z = T1_z + t # 求和得到加速度向量(替换为你的实际求和/加速度计算逻辑) a_x = sp.diff(T2_x, t, 2) + sp.diff(T2_x, x)*x a_y = sp.diff(T2_y, t, 2) + sp.diff(T2_y, y)*y a_z = sp.diff(T2_z, t, 2) + sp.diff(T2_z, z)*z # 生成完整的加速度向量表达式 a_expr = sp.Matrix([a_x, a_y, a_z]) # lambdify生成单一可调用函数 accel_func = sp.lambdify((t, x, y, z), a_expr, modules=['numpy'])
这种方法直接通过符号代入生成完整表达式,避开了Sympy自动CSE的bug,同时得到的单一函数可直接用于后续的符号导数计算(基于a_expr对原变量求导)和codegen。
2. 包装多lambdify函数为单一可调用对象(兼顾效率与符号操作)
如果完整符号表达式过于庞大导致lambdify耗时,可将多个辅助lambdify函数包装成一个单一函数,同时保留原始符号表达式用于后续求导和代码生成:
import sympy as sp import numpy as np # 定义所有中间符号表达式(同方法1) t, x, y, z = sp.symbols('t x y z') T1_x = sp.cos(t)*x - sp.sin(t)*y T1_y = sp.sin(t)*x + sp.cos(t)*y T1_z = z T2_x = T1_x + sp.sin(t)*T1_z T2_y = T1_y - sp.cos(t)*T1_z T2_z = T1_z + t a_x = sp.diff(T2_x, t, 2) + sp.diff(T2_x, x)*x a_y = sp.diff(T2_y, t, 2) + sp.diff(T2_y, y)*y a_z = sp.diff(T2_z, t, 2) + sp.diff(T2_z, z)*z # 生成各步骤的辅助lambdify函数 T1_func = sp.lambdify((t, x, y, z), [T1_x, T1_y, T1_z], modules=['numpy']) T2_func = sp.lambdify((t, t1_x, t1_y, t1_z), [T2_x, T2_y, T2_z], modules=['numpy']) a_func = sp.lambdify((t, t2_x, t2_y, t2_z, x, y, z), [a_x, a_y, a_z], modules=['numpy']) # 包装为单一对外函数 def accel_func(t, x, y, z): t1_x, t1_y, t1_z = T1_func(t, x, y, z) t2_x, t2_y, t2_z = T2_func(t, t1_x, t1_y, t1_z) return np.array(a_func(t, t2_x, t2_y, t2_z, x, y, z)) # 后续符号求导仍基于原始符号表达式 da_dx = sp.diff(a_x, x) da_dx_func = sp.lambdify((t, x, y, z), da_dx, modules=['numpy']) # codegen直接针对完整符号表达式生成代码 sp.codegen(('acceleration', sp.Matrix([a_x, a_y, a_z])), language='python', filename='accel_code')[0]
这种方式既保留了拆分辅助函数的运行效率,又能基于原始符号表达式完成后续的导数计算和代码生成需求。
3. 用Numba加速lambdify生成的单一函数
如果求值效率是核心痛点,可将numba作为lambdify的后端,对单一函数进行JIT编译,大幅提升运行速度:
# 基于方法1的完整符号表达式a_expr accel_func = sp.lambdify((t, x, y, z), a_expr, modules=['numba', 'numpy'])
注意:Numba对Sympy的部分符号操作支持有限,若出现兼容性问题,可先通过sp.simplify简化表达式,或手动替换Numba不支持的函数为numpy兼容实现。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

