0

I have a very complicated non-linear function f. I want to get taylor series till degree n in a form of sympy expression for the function f at value x. f is a regular python function not a sympy expression. Output of get_polynomial should be a sympy expression.

Is there any function that will get taylor-series of a function?

from math import sin, cos, log, e

def f(x):
    # a very complicated function
    y = sin(x) + cos(x) + log(abs(x)+2)**2/e**2 + sin(cos(x/2)**2) + 1
    return y

def get_polynomial(function, x, degree):
    #    .......
    #    using Taylor Series
    #    .......
    return sympy_expression_for_function_at_value_x

Output:

get_polynomial(sin, 0, 3) ---> 0 + x + 0*x**2 + (1/6)*x**3
get_polynomial(lambda x: e**x, 0, 1) --> 1 + x

In a similar manner I wanna calculate get_polynomial(f, 0, 3)

Nitin Sharma
  • 140
  • 9
  • Possible duplicate of [How to do a symbolic taylor expansion of an unknown function $f(x)$ using sympy](https://stackoverflow.com/questions/16869587/how-to-do-a-symbolic-taylor-expansion-of-an-unknown-function-fx-using-sympy) – Auxilus Dec 30 '18 at 19:33
  • Am I correct in thinking that you want your *input* function to be a regular Python function but you want your *output* polynomial to be a sympy polynomial? If so, how do you expect exact output in sympy to result from approximate functions in Python (since floating point calculations in Python are only approximate)? Or do you want your input function to be a sympy function, as in the link in the "possible duplicate" comment? – Rory Daulton Dec 30 '18 at 19:33
  • Yes, Input function should be a regular python function and out should be a sympy expression @RoryDaulton – Nitin Sharma Dec 30 '18 at 19:37
  • Then it would be practically impossible to get, for example, the value `1/6` in the polynomial for `sin`. Python floating-point cannot even store that value exactly, much less calculate it. A Python routine could get a constant close to `1/6` but not exactly equal to it. You could approximate that value to a fraction but you would need to give some kind of tolerance, and you could get a false fraction for a value that actually should be irrational. – Rory Daulton Dec 30 '18 at 20:44
  • How precise should the output polynomial be? Since you only want the first n members of the taylor series, you already accept some error. – Yakov Dan Dec 31 '18 at 16:24
  • I just need approximate values of Co-efficients and it doesn't have to be in form of a fraction. @RoryDaulton a floating point value close to 1/6 would work perfectly fine. Even 10% of error in estimated co-efficients will be acceptable. Thanks. – Nitin Sharma Jan 02 '19 at 05:46
  • @YakovDan Even 10% of error in estimated co-efficients will be acceptable. Thanks. – Nitin Sharma Jan 02 '19 at 05:47

1 Answers1

2

The following code is close to what you're looking for. What this does it to parse the code the of the function you wish you expand into a Taylor series, convert it into a symbolic representation using Sympy and then compute the Taylor expansion.

One limitation is that you need to have an explicit function definition so you can't use lambda expressions. This can be solved with further work. Otherwise the code does what you ask for. Note that when you define a function, it has to contain a line of the form y = ... for this code to work

from inspect import *
import sympy

def f(x):
    # a very complicated function
    y = sin(x) + cos(x) + log(abs(x)+2)**2/e**2 + sin(cos(x/2)**2) + 1
    return y

def my_sin(x):
    y = sin(x)
    return y

def my_exp(x):
    y = e**x
    return y 


x = sympy.Symbol('x')

def get_polynomial(function, x0, degree):
    # parse function definition code

    lines_list  = getsource(function).split("\n")
    for line in lines_list:
        if '=' in line:
            func_def = line

    elements = func_def.split('=')
    line = ' '.join(elements[1:])
    sympy_function = sympy.sympify(line)

    # compute taylor expansion symbolically 
    i = 0
    taylor_exp = sympy.Integer(0)
    while i <= degree:
        taylor_exp = taylor_exp + (sympy.diff(sympy_function,x,i).subs(x,x0))/(sympy.factorial(i))*(x-x0)**i
        i += 1


    return taylor_exp

print (get_polynomial(my_sin,0,5))
print (get_polynomial(my_exp,0,5))
print (get_polynomial(f,0,5))
Yakov Dan
  • 2,157
  • 15
  • 29
  • Thank you for your efforts. Your solution seems to work really well. If we could get simplified value of co-efficients then that'd be great. e.g. in get_polynomial(my_exp,0,5) if we could get co-eff of x**2 to be (1/2) or 0.5 or ~0.5 instead of log(e)**2/2 – Nitin Sharma Jan 02 '19 at 05:58
  • just use `E` instead of `e` when writing functions, for instance `y = E**x` instead of `y=e**x`. – Yakov Dan Jan 02 '19 at 10:58