我们需要两个微分算子矩阵 [B]
和 [C]
,例如:
B = sympy.Matrix([[ D(x), D(y) ],
[ D(y), D(x) ]])
C = sympy.Matrix([[ D(x), D(y) ]])
ans = B * sympy.Matrix([[x*y**2],
[x**2*y]])
print ans
[x**2 + y**2]
[ 4*x*y]
ans2 = ans * C
print ans2
[2*x, 2*y]
[4*y, 4*x]
这也可以应用于计算矢量场的卷曲,如:
culr = sympy.Matrix([[ D(x), D(y), D(z) ]])
field = sympy.Matrix([[ x**2*y, x*y*z, -x**2*y**2 ]])
要使用Sympy解决这个问题,必须创建以下Python类:
import sympy
class D( sympy.Derivative ):
def __init__( self, var ):
super( D, self ).__init__()
self.var = var
def __mul__(self, other):
return sympy.diff( other, self.var )
当差分算子矩阵在左边相乘时,这个类就解决了 . 这里只有当要区分的函数已知时才执行 diff
.
要在差分运算符矩阵乘以右侧时进行解决,必须按以下方式更改核心类 Expr
中的 __mul__
方法:
class Expr(Basic, EvalfMixin):
# ...
def __mul__(self, other):
import sympy
if other.__class__.__name__ == 'D':
return sympy.diff( self, other.var )
else:
return Mul(self, other)
#...
它工作得很好,但在Sympy中应该有一个更好的原生解决方案来处理这个问题 . 有谁知道它可能是什么?
4 回答
此解决方案应用其他答案的提示和from here .
D
运算符可以定义如下:仅在从左侧乘以时才考虑,因此
D(t)*2*t**3 = 6*t**2
但2*t**3*D(t)
什么都不做D
使用的所有表达式和符号必须is_commutative = False
使用
evaluateExpr()
在给定表达式的上下文中评估从找到
D
操作符并将mydiff()
*应用于相应的右边部分的表达式从右向左移动*:使用mydiff代替diff来允许创建更高阶D,如mydiff(D(t),t)= D(t,t)
D
中__mul__()
内的diff
仅供参考,因为在当前解决方案中,evaluateExpr()
实际上执行区分作业 . 创建了一个python mudule并保存为d.py
.例1:矢量场的卷曲 . 请注意,使用
commutative=False
定义变量很重要,因为它们在Mul().args
中的顺序会影响结果,请参阅this other question .示例2:结构分析中使用的典型Ritz近似 .
已创建
print_to_file()
函数以快速检查大表达式 .差异 operators 不存在于SymPy的核心中,即使它们存在"multiplication by an operator"而不是"application of an operator",也是滥用SymPy不支持的符号 .
[1]另一个问题是SymPy表达式只能从
sympy.Basic
的子类构建,所以当输入为sympy_expr+D(z)
时,class D
可能只会引发错误 . 这就是(expression*D(z)) * (another_expr)
失败的原因 .(expression*D(z))
无法构建 .此外,如果
D
的参数不是单个Symbol
,则不清楚您对此运算符的期望 .最后,
diff(f(x), x)
(其中f
是一个符号未知函数)返回一个未经评估的表达式,因为你观察的只是因为当f
未知时,没有任何其他可以明智地返回 . 之后,当您替换expr.subs(f(x), sin(x))
时,将对导数进行求值(最坏的情况下,您可能需要调用expr.doit()
) .[2]对你的问题没有优雅的解决方案 . 我建议解决问题的方法是覆盖
Expr
的__mul__
方法:而不是仅仅将表达式树相乘,它将检查左表达式树是否包含D
的实例,并且它将应用它们 . 显然,如果要添加新对象,则不会缩放 . 这是一个长期以来已知的问题设计问题 .编辑:[1]只需要允许创建包含
D
的表达式 . [2]对于包含更多只有一个D
工作的表达式是必要的 .如果你想要正确的乘法工作,你需要从
object
继承 . 这将导致x*D
回落到D.__rmul__
. 但是,我无法想象这是高优先级,因为操作员永远不会从右边应用 .目前无法实现自动运行的操作员 . 要真正完成工作,你需要http://code.google.com/p/sympy/issues/detail?id=1941 . 另请参阅https://github.com/sympy/sympy/wiki/Canonicalization(随意编辑该页面) .
但是,您可以使用来自stackoverflow问题的想法创建一个大部分时间都可以工作的类,对于它不处理的情况,编写一个通过表达式的简单函数,并将运算符应用于尚未处理的情况 . 应用了 .
顺便说一下,使用微分算子作为"multiplication"时要考虑的一点是它是非关联的 . 即,
(D*f)*g
=g*Df
,而D*(f*g)
=g*Df + f*Dg
. 因此,当你做的事情不需要表达的某些部分而不是整个事情时,你需要小心 . 例如,D*2*x
会因此而给出0
. SymPy无处不在假设乘法是关联的,因此在某些时候可能会错误地做到这一点 .如果这成为一个问题,我建议转储自动应用程序,并只使用一个经过并应用它的功能(正如我上面提到的,你仍然需要) .