如何将可调用函数添加到 Sympy 表达式

How to add a callable function to a Sympy expression

如果我有一个表达式 x = Symbol('x')f1=x**2,我想进一步添加一些 f2,其中 f2 = interp1d(t, y) 是 scipy 插值。如何将 f2 变成一个表达式,使我有类似 f = x**2 + f2(x) 的东西,以便我以后可以将 f 计算为 f.subs(x, some_number)

由于代码规范,我无法单独评估 f1f2 然后添加结果数字,我需要能够将其添加到现有的 sympy 表达式中并且使用 .subs()

之类的东西对其进行评估

一种非常冒险的方法是为您的数值函数创建一个包装对象,如下所示:

from sympy import *
import numpy as np
var("x")

# symbolic expression
f1 = cos(x)
# numerical function
f2 = lambda t: np.sin(t)

class MyFunc(Expr):
    """Create a symbolic wrapper to a numerical function."""
    
    def __new__(cls, arg, **kwargs):
        obj = Expr.__new__(cls, **kwargs)
        obj._custom_func = arg
        return obj
    
    def _subs(self, old, new, **hints):
        return self._custom_func(float(new))

expr = f1 + MyFunc(f2)
expr.subs(x, np.pi/4)
# out: 1.41421356237309

一种方法,但它需要 hard-coding 在 class:

中调用的函数
f2 = lambda t: np.sin(t)

class MyFunc(Function):
    @classmethod
    def eval(cls, arg):
        arg = sympify(arg, strict=True)
        if arg.is_Number:
            return sympify(f2(float(arg)), strict=True)

更像 Davide 的回答,但有一些修正:

class FuncWrapper(Symbol):
    """Wraps a python callable as a Basic instance"""
    def __new__(cls, func, name):
        obj = super().__new__(cls, name)
        obj._wrapped = func
        return obj

    @property
    def wrapped(self):
        return self._wrapped

    def _hashable_content(self):
        return (self.wrapped,) # needed for __eq__

    def eval(self, arg):
        if arg.is_Number:
            return sympify(self.wrapped(float(arg)))

    def __call__(self, arg):
        return Call(self, arg)


class Call(Function):
    @classmethod
    def eval(cls, func, arg):
        arg = sympify(arg)

        result = func.eval(arg)
        if result is not None:
            return result

这样你就有了:

In [61]: f = FuncWrapper(np.sin, 'f')

In [62]: x + f(x)
Out[62]: x + Call(f, x)

In [63]: _.subs(x, 1)
Out[63]: 1.84147098480790