If I have an expression x = Symbol('x')
and f1=x**2
and I want to further add some f2
where f2 = interp1d(t, y)
is scipy interpolation. How does one turn f2
into an expression such that I have somthing like f = x**2 f2(x)
so that I can later evaluate f
as f.subs(x, some_number)
?
Due to specification of the code, I can't evaluate f1
and f2
separatelly and then add the resulting numbers, I need to be able to add it to an existing sympy expression and evaluate it using something like .subs()
CodePudding user response:
One way but it requires hard-coding the function to be called in the 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)
More like Davide's answer but with a couple of fixes:
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
With that you have:
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
CodePudding user response:
One very risky way would be to create a wrapper object for your numerical function, like this:
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