【问题标题】:lambdify a sympy expression that contains a Derivative of UndefinedFunctionlambdify 包含 UndefinedFunction 的导数的 sympy 表达式
【发布时间】:2015-04-28 13:15:31
【问题描述】:

我有几个未定义函数的表达式,其中一些包含该函数的相应(未定义)导数。函数及其导数都仅作为数值数据存在。我想从我的表达式中创建函数,然后使用相应的数值数据调用该函数以数值计算表达式。不幸的是,我遇到了lambdify的问题。

考虑以下简化示例:

import sympy
import numpy

# define a parameter and an unknown function on said parameter
t = sympy.Symbol('t')
s = sympy.Function('s')(t)

# a "normal" expression
a = t*s**2
print(a)
#OUT: t*s(t)**2

# an expression which contains a derivative
b = a.diff(t)
print(b)
#OUT: 2*t*s(t)*Derivative(s(t), t) + s(t)**2

# generate an arbitrary numerical input
# for demo purposes lets assume that s(t):=sin(t)
t0 = 0
s0 = numpy.sin(t0)
sd0 = numpy.cos(t0)

# labdify a
fa = sympy.lambdify([t, s], a)
va = fa(t0, s0)
print (va)
#OUT: 0

# try to lambdify b
fb = sympy.lambdify([t, s, s.diff(t)], b)  # this fails with syntax error
vb = fb(t0, s0, sd0)
print (vb)

错误信息:

  File "<string>", line 1
    lambda _Dummy_142,_Dummy_143,Derivative(s(t), t): (2*_Dummy_142*_Dummy_143*Derivative(_Dummy_143, _Dummy_142) + _Dummy_143**2)
                                           ^
SyntaxError: invalid syntax

显然 Derivative 对象没有正确解析,我该如何解决?

作为 lambdify 的替代方案,我也愿意使用基于 theano 或 cython 的解决方案,但我在使用相应的打印机时遇到了类似的问题。

感谢任何帮助。

【问题讨论】:

    标签: python python-3.x sympy


    【解决方案1】:

    据我所知,问题源于lambdify 函数中不正确/不幸的虚拟化过程。我已经编写了自己的虚拟化函数,在将它们传递给lambdifying之前,我将其应用于参数和表达式。

    def dummify_undefined_functions(expr):
        mapping = {}    
    
        # replace all Derivative terms
        for der in expr.atoms(sympy.Derivative):
            f_name = der.expr.func.__name__
            var_names = [var.name for var in der.variables]
            name = "d%s_d%s" % (f_name, 'd'.join(var_names))
            mapping[der] = sympy.Symbol(name)
    
        # replace undefined functions
        from sympy.core.function import AppliedUndef
        for f in expr.atoms(AppliedUndef):
            f_name = f.func.__name__
            mapping[f] = sympy.Symbol(f_name)
    
        return expr.subs(mapping)
    

    这样使用:

    params = [dummify_undefined_functions(x) for x in [t, s, s.diff(t)]]
    expr = dummify_undefined_functions(b)
    fb = sympy.lambdify(params, expr)
    

    显然这有点脆弱:

    • 没有防范名称冲突
    • 也许不是最好的命名方案:df_dxdy for Derivative(f(x,y), x, y)
    • 假设所有导数的形式为: Derivative(s(t), t, ...)s(t)UndefinedFunctiontSymbol。我不知道如果 Derivative 的任何参数是一个更复杂的表达式会发生什么。我有点认为/希望(自动)简化过程会将任何更复杂的导数简化为由“基本”导数组成的表达式。但我当然不会防备。
    • 大部分未经测试(我的特定用例除外)

    除此之外它工作得很好。

    【讨论】:

      【解决方案2】:

      at here讨论了类似的问题

      您只需要定义自己的函数并将其导数定义为另一个函数:

      def f_impl(x):
          return x**2
      
      def df_impl(x):
          return 2*x
      
      class df(sy.Function):
          nargs = 1
          is_real = True
          _imp_ = staticmethod(df_impl)
      
      class f(sy.Function):
          nargs = 1
          is_real = True
          _imp_ = staticmethod(f_impl)
      
          def fdiff(self, argindex=1):
              return df(self.args[0])
      
      t = sy.Symbol('t')
      print f(t).diff().subs({t:0.1})
      
      expr = f(t) + f(t).diff()
      expr_real = sy.lambdify(t, expr)
      print expr_real(0.1)
      

      【讨论】:

      • 感谢您的回答,不幸的是它不适用于这里。我故意使用 UndefinedFunction,因为函数定义不以封闭形式提供。只有离散的数字数据点可用。据我所知,问题源于lambdify 函数中不正确/不幸的虚拟化过程。我已经编写了我自己的虚拟化函数,我将其应用于参数以及表达式,然后再对其进行羔羊化。我会把它作为anwser发布。
      • 在这种情况下,函数 f 将是未定义的。当你尝试用数字化或评估它时,它将被实现。
      • hm,那么如果我遗漏了_imp_ 部分(因为我没有它们)会怎样?还能用吗?
      • 会的。试试class f(sympy.Function): pass t = sympy.Symbol('t') print f(0.1) print f(t).diff()
      • 我的建议是一种解决方法。它不允许您替换导数,它允许您通过另一个函数更改子字符串Derivative(s(t), t),比如说g(t)。之后,您可以将 g(t) 用作lambdify 中的参数。另一种解决方案是使用subs函数:v = sympy.Symbol('v')(t); b1 = b.subs({s.diff(t): v}); fb = sympy.lambdify([t, s, v], b1);
      【解决方案3】:

      首先,您可以继续使用implemented_function 函数将s(t) 的数值实现与符号函数联系起来,而不是UndefinedFunction。

      然后,如果您受限于定义函数的离散数值数据,该函数的导数出现在麻烦的表达式中,大多数时候,导数的数值评估可能来自有限差分。作为替代方案,sympy 可以自动用有限差分替换导数项,并将结果表达式转换为 lambda。例如:

      import sympy
      import numpy
      from sympy.utilities.lambdify import lambdify, implemented_function
      from sympy import Function
      
      # define a parameter and an unknown function on said parameter
      t = sympy.Symbol('t')
      s = implemented_function(Function('s'), numpy.cos)
      
      print('A plain ol\' expression')
      a = t*s(t)**2
      print(a)
      
      print('Derivative of above:')
      b = a.diff(t)
      print(b)
      
      # try to lambdify b by first replacing with finite differences
      dx = 0.1
      bapprox = b.replace(lambda arg: arg.is_Derivative,
                          lambda arg: arg.as_finite_difference(points=dx))
      print('Approximation of derivatives:')
      print(bapprox)
      fb = sympy.lambdify([t], bapprox)
      
      t0 = 0.0
      vb = fb(t0)
      print(vb)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-04
        • 1970-01-01
        相关资源
        最近更新 更多