我想求一个复杂函数的导数。不幸的是,当我构造要求导的表达式时,它会将所有子表达式扩展至紧邻的符号。因此,一旦我对最终表达式进行微分,它就会膨胀到难以控制的大小。我曾尝试手动将一些子表达式替换回最终结果中之前的形式,但由于表达式构造过程中的重构,错失了很多简化的机会。
这只是我想要推导的第一阶段,即使尝试替换一些用于构建它的表达式,它已经变得非常臃肿。
from sympy import *
aX, aY, aZ = symbols('aX aY aZ')
rotInc = Matrix(3,1,[aX, aY, aZ])
theta = sqrt((rotInc.T @ rotInc)[0,0])
incQuat = Quaternion.from_axis_angle(rotInc/theta, theta*2)
qX, qY, qZ, qW = symbols('qX qY qZ qW')
baseQuat = Quaternion(qW, qX, qY, qZ)
poseQuat = incQuat * baseQuat
d4 = diff(poseQuat, aX)
d4s = d4.subs({
incQuat.a: symbols('iW'),
incQuat.b: symbols('iX'),
incQuat.c: symbols('iY'),
incQuat.d: symbols('iZ'),
theta: symbols('theta')
})
我知道cse
(公共子表达式消除),这表明存在某种系统可以保留命名的子表达式。我希望 sympycse
在我构造表达式时构建一个类似 returns 的结构,并且只在必要时(例如在微分过程中)用子表达式的组件替换它。这样可以在最终的微分过程中保留大部分这些符号,从而得到更清晰、可立即使用的输出。
是否有这样一种在 sympy 中构造表达式的模式/方法,或者其他可以帮助我保持最终表达式简单的方法?谢谢!
这不是一个答案,因为我不知道你想得到什么。但是,我理解你的问题。你知道
theta
是 的函数aX, aY, aZ
, 的分量也是 的函数incQuat
。如果我们像这样处理未定义的应用函数会怎么样?这是第一步的表达式。然后,当你准备好进行实际计算时,请代入字典:
最终你会得到非常长的表达式......
我以为这在 SymPy 的某个地方,但也许在准备编译函数(或类似的东西)时用到了它。不过,按照你的想法(在这个问题上可能有点多余):
因此,借助@Davide_sd 提供的函数提示,我创建了一个通用方法,可以让我非常轻松地控制子步骤的拆分方式。基本上,我手动推导拆分出的函数,但与 cse 非常相似,将结果保存在字典中以在所有实例之间共享。
组成计算的基本表达式是输入,永远不会被修改,推导列表以您想要推导的内容为种子(多个表达式也可以),并且它将根据需要使用表达式列表递归地推导它们。
最后,我仍然可以使用 cse 来 a) 如果需要,将其转换为该格式,以及 b) 分解出更常见的实例。
它与我的小示例配合得很好,可能会随着我为需要推导的函数添加更多复杂性而更新它。