代码之家  ›  专栏  ›  技术社区  ›  Rob Hall

在Sympy中表示一个常量符号,使其不是free_symbol

  •  0
  • Rob Hall  · 技术社区  · 5 年前

    应用程序 我想创建一个python函数(例如。, Laplacian(expr) ). 拉普拉斯算子被定义为取 expr 对于每个变量(例如。, Laplacian(f(x,y,z)) 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() == True g(E).is_constant() == True 因为它是一个数字。

    注意事项

    1. 我无法注册 c 作为单例,因为它只针对这个特定的证明或表达式进行定义。
    2. 我不能用像这样的价值观来构建它 E 因为没有特定的数值可以分配给它。
    3. 我不能简单地添加一个 constants 关键字to Laplacian ,因为我不知道可能出现的所有常量(就像添加这些常量没有意义一样 constants=[1,2,3,4,...] solve() ).

    4. 我不能简单地添加一个 variables 关键字to 拉普拉斯 ,因为我不知道表达式中出现的变量。

    预期用途如下:

    >>> 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
    

    拓展目标: 如果有一个任意的常数符号,以同样的方式吸收其他常数项,那就太棒了 constantsimp 操作。考虑引入一个积分常数 c 然后将该表达式乘以 I 就代数而言, cI=c 在不失一般性的前提下。

    1 回复  |  直到 5 年前
        1
  •  4
  •   Rob Hall    5 年前

    注:

    根据Oscar Benjamin对问题的评论,当前构建sympy风格方法的最佳实践(如 Laplacian )是通过a constants variables 关键字转换为方法。在应用以下解决方案时,请记住这一点。此外, free_symbols Sympy中有许多应用程序,因此使用另一个已建立语义的类可能会产生意想不到的副作用。

    (正如本杰明先生指出的那样,如果出现更好的解决方案,我不会接受我自己的解决方案

    解决方案

    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)
    

    在中测试时,上述代码片段会产生以下输出 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}
    

    请注意,虽然 g(C).is_constant()==True ,我们看到了 g(x).is_constant() == None ,以及 g(C,x).is_constant() == None 因此,我只断言这两个应用程序具有一致的接口。