komodovaran_
komodovaran_

Reputation: 2012

Generic way to write up SymPy integration?

Right now, to integrate a function fx with SymPy I would do the following:

from sympy.abc import alpha as _alpha_, beta as _beta_, x as _x_

sym_args = _alpha_, _beta_

fx_definite_integral = sympy.integrate(fx(_x_, *sym_args), (_x_, xmin, xmax))

But this requires me to know beforehand what symbols I might need for a given function. But what if I plugged in a different function, with parameters, say, A, B, Y, Z, Q, W?

Instead of manually assigning symbols in SymPy, is there a way to generically assign symbols - basically, my sym_args, based on the input function?

Ideally

sym_args = sympy.all_the_symbols_I_need_for_random_function(fx)

Upvotes: 2

Views: 277

Answers (2)

javidcf
javidcf

Reputation: 59731

The problem is a bit ill-defined because, after all, you need to know something about the arguments of fx, right? For example, fx should have at least one argument for the x; is it always the first argument, or the argument called x, which may or may not be the first? Should the rest of arguments be given a specific sequence of names, such as alpha, beta, etc. or instead use symbols with the name of the argument? What if the arguments have default values?

I'll give one possible approach for a simple example, then you can choose how to implement it exactly for your case. Let's have this function:

def fx(x, a, b, c):
    return x * (a + (b / c))

In order to extract information about the function arguments, you can use the inspect

import inspect
fx_args = inspect.getfullargspec(fx).args  # fx_args <- ['x', 'a', 'b', 'c']

inspect.getfullargspec returns a namedtuple with information about the function arguments, you can check the docs to see if you need something else (e.g. to ignore parameters with default values). Now you can convert those to SymPy symbols:

import sympy
fx_argsym = sympy.symbols(fx_args)  # fx_argsym <- [x, a, b, c]

Here you could use a different strategy. For example, if you wanted to have the first argument be always x and the rest of arguments be always Greek letters (as long as you don't have too many arguments) you could do:

import sympy.abc
fx_argsym = [sympy.abc.x] + list(sympy.symbols(sympy.abc.greeks[:len(fx_args) - 1]))
# fx_argsym <- [x, alpha, beta, gamma]

You can manipulate fx_argsym however you want to suit your needs. When you get get it right, you can call sympy.integrate as usual:

fx_definite_integral = sympy.integrate(fx(*fx_argsym), (_x_, xmin, xmax))

Note that if you didn't make sure that x was in fx_argsym you may get an error, but that is easy to check for example with:

assert _x_ in fx_argsym

Upvotes: 1

asmeurer
asmeurer

Reputation: 91580

You can use

f = Function('f')
expr.Integral(f(x), (x, xmin, xmax))

and then use expr.replace(f, your_function) to replace f with your function. You will need to curry your_function so that it accepts one parameter to match f. As far as Integral is concerned, it only needs to know that f depends on x. The rest of the (constant) variables can be "in" f.

For instance, if your expression is x + A + B, you can use expr.replace(f, lambda x: x + A + B).

Upvotes: 1

Related Questions