应用程序
我想创建一个 python 函数(例如Laplacian(expr))。expr拉普拉斯算子被定义为取关于每个变量的二阶偏导数之和(例如, Laplacian(f(x,y,z))is diff(f,x,x) + diff(f,y,y) + diff(f,z,z)。在表达式中,可能有任意常量c,k等,就表达式而言,它们不是变量。只是由于不能求导数diff(f,126),因此对表达式求导c是没有定义的。
我需要能够从表达式中提取非常量的自由符号。
问题c = Symbol('c', constant=True, number=True)虽然我可以在 Sympy 中
构建,c.is_constant()但计算结果为False. 同样,g(c).is_constant()评估结果为 false。对于我的应用程序,该符号应该具有与和c完全相同的行为,因为它是一个数字。E.is_constant() == Trueg(E).is_constant() == True
注意事项
c为单例,因为它仅针对此特定证明或表达式进行定义。E,因为没有可以分配给它的特定数值。我不能简单地将constants关键字添加到,因为我不知道可能出现的所有此类常量(就像添加到Laplacian没有意义一样)。constants=[1,2,3,4,...]solve()
我不能简单地variables向 中添加关键字Laplacian,因为我不知道表达式中出现的变量。
期望的用法如下:
>>> C = ... # somehow create the constant
>>> symbols_that_arent_constant_numbers(g(C))
set()
>>> symbols_that_arent_constant_numbers(g(C, x))
{x}
>>> g(C).is_constant()
True
Run Code Online (Sandbox Code Playgroud)
延伸目标:如果有一个任意常数符号能够以相同的方式吸收其他常数项,那就太棒了constantsimp。c考虑在表达式中引入积分常数,然后将该表达式乘以I。就代数而言,cI=c不失任何一般性。
笔记
根据 Oscar Benjamin 对问题的评论,构建 sympy 风格的方法(如 )时的当前最佳实践是将or关键字Laplacian传递到方法中。应用以下解决方案时请记住这一点。此外,Sympy 中有许多应用程序,因此使用另一个已建立语义的类可能会产生意想不到的副作用。constantsvariablesfree_symbols
(如果出现更好的解决方案,我不会接受我自己的解决方案,正如本杰明先生指出的那样,存在许多未解决的相关问题。)
解决方案
Sympy 提供了一种创建此类常量的机制:sympy.physics.units.quantities.Quantity。它的行为等同于Symbol单例常量,但最值得注意的是它并不作为自由符号出现。这可以帮助防止代码将其解释为可微分的变量等。
from sympy.physics.units.quantities import Quantity
C = Quantity('C')
print("C constant? : ", C.is_constant())
print("C free symbols : ", C.free_symbols)
print("x constant? : ", x.is_constant())
print("g(C) constant? : ", g(C).is_constant())
print("g(x) constant? : ", g(x).is_constant())
print("g(C,x) constant : ", g(C,x).is_constant())
print("g(C) free symbols : ", g(C).free_symbols)
print("g(C,x) free symbols: ", g(C,x).free_symbols)
assert C.is_constant()
assert C.free_symbols == set([])
assert g(C).is_constant()
assert g(C, x).is_constant() == g(x).is_constant() # consistent interface
assert g(C).free_symbols == set([])
assert g(C, x).free_symbols == set([x])
assert [5/C] == solve(C*x -5, x)
Run Code Online (Sandbox Code Playgroud)
当在 中测试时,上面的代码片段会产生以下输出sympy==1.5.1:
C constant? : True
C free symbols : set()
x constant? : False
g(C) constant? : True
g(x) constant? : None
g(C,x) constant : None
g(C) free symbols : set()
g(C,x) free symbols: {x}
Run Code Online (Sandbox Code Playgroud)
请注意,虽然g(C).is_constant()==True,我们看到了g(x).is_constant() == None,以及g(C,x).is_constant() == None。因此,我只断言这两个应用程序具有一致的界面。