1

I have made a calculator that approximates any given function as an input. They later I want it to calculate an integral, but after writing:

function    = str(input("The function that must be expanded and integrated: "))

It doesn't print a number but instead a value. This is my code:

from sympy.functions import sin,cos,tan
from sympy.abc import x
from sympy import *
from sympy import series
from math import *
function    = str(input("The function that must be expanded and integrated: "))
x0          = int(input("Point of development: "))
n           = int(input("Amount of expressions: "))

print(series(function, x, x0, n))

N = int(input("Amount of summs (Bigger number is more accurate but takes longer time): "))
a = int(input("Integrate from: "))
b = int(input("Integrate to: "))

# We will use the midpoint method to integrate the function

def integrate(N, a, b):
    def f(x):
        return series(function, x, x0, n)
    value=0
    value=2
    for n in range(1, N+1):
        value += f(a+((n-(1/2))*((b-a)/N)))
    value2 = ((b-a)/N)*value
    return value2

print("...................")
print("Here is your answer: ")
print(integrate(N, a, b))

I think, it's because my input is a string. However I can't choose my input to be an integer, because exp(-x**2) isn't an integer. If that's the case, how can I input any function in my calculater and still get a value?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Nikolai
  • 39
  • 6
  • You need to map the string to a function to execute. In case you want to input `'exp(-x**2)'` as string, you would also need to parse it intos stuffs to do – Patrick Artner Sep 10 '20 at 11:58
  • Might be a dupe of [Evaluating-a-mathematical-expression-in-a-string](https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string) – Patrick Artner Sep 10 '20 at 12:00
  • why do you set `value=0` and on the very next line `value=2`? why are `N`, `a` and `b` parameters of `integrate`, but not `function`, `x0` and `n`. I would prefer wither using all as parameters, or none of them. – Jan Stránský Sep 10 '20 at 13:14
  • why do you use both Taylor polynomial approximation and midpoint approximation? Wouldn't it be better *either* use midpoint rule directly to the original function *or* integrate precisely/analytically the Taylor polynomial? – Jan Stránský Sep 10 '20 at 13:34

1 Answers1

1

There a some significant issues in your code:

  • inside integrate, you are using local variable n, but inside f(x) you consider it to be the global n (but the local is used, which is what you want, just print n inside the f(x)). The same holds for x as a global variable and parameter in f(x). Do not use same names for global and local variables if you want to use both in the same scope.
  • the return value of f(x) is a sympy epxression, not a single value, that's why you get the output what you get.

After some refactoring and using subs and removeO:

from sympy.functions import sin,cos,tan
from sympy.abc import x
from sympy import series

function    = str(input("The function to be expanded and integrated: "))
x0          = int(input("Point of development: "))
n           = 1 + int(input("Degree: "))
# input 0 -> n=1 -> constant  (1 term, constant)
# input 1 -> n=2 -> linear    (2 terms, constant + linear)
# input 2 -> n=3 -> quadratic (3 terms, constant + linear + quadratic)
# ...

print(series(function, x, x0, n))

N = int(input("Amount of summs (Bigger number is more accurate but takes longer time): "))
a = int(input("Integrate from: "))
b = int(input("Integrate to: "))

# We will use the midpoint method to integrate the function

def integrate(function, x0, n, N, a, b): # using the approach with all variables as parameters
    taylor = series(function, x, x0, n) # the same expression for the function, create it once
    taylor = taylor.removeO() # do not use O term (may corrups subs below)
    dx = (b-a)/N # also computed just once
    def f(v):
        return taylor.subs(x,v) # taylor is expression, return value is float evaluated with substituted x by v
    return dx * sum(f(a+(i+1/2)*dx) for i in range(N)) # simple sum function, can be rewriten using a for loop

print("...................")
print("Here is your answer: ")
print(integrate(function, x0, n, N, a, b))

Some outputs for x**2 integrated from x=0 to x=2 expanded at x=1. Analytical result is 8/3=2.6666666....

x**2, 1, 0, 5, 0, 2 => 2.0 # constant approximation
x**2, 1, 1, 5, 0, 2 => 2.0 # linear approximation
x**2, 1, 2, 5, 0, 2 => 2.64 # quadratic approximation - exact function
x**2, 1, 2, 10, 0, 2 => 2.66
x**2, 1, 2, 100, 0, 2 => 2.6666
x**2, 1, 2, 1000, 0, 2 => 2.666666

You can use lambdify to "convert a SymPy expression into a function that allows for fast numeric evaluation". For the case of N=1000 the speedup is significant.

from sympy.utilities.lambdify import lambdify
def integrate(function, x0, n, N, a, b):
    taylor = series(function, x, x0, n)
    taylor = lambdify(x,taylor.removeO()) # here
    dx = (b-a)/N
    def f(v):
        return taylor(v) # here
    return dx * sum(f(a+(i+1/2)*dx) for i in range(N))
Jan Stránský
  • 1,671
  • 1
  • 11
  • 15
  • Thank you, the only thing is, let's say I plot in `exp(-x**2)` as the function, it is waaay off, why is that? – Nikolai Sep 11 '20 at 13:33
  • 1
    Please provide the other parameters. As I asked below OP, you do **two** approximations, each one producing some error. Either use Taylor polynomial approximation or the midpoint rule, you should get better results – Jan Stránský Sep 11 '20 at 13:39
  • Yeah i figured it out. When approximating the function with 1000 degrees and 1000 sums it's much more accurate. I will attempt to implement lambdify to speed up the calculation. Thank you! – Nikolai Sep 11 '20 at 13:45
  • I am still curious why you use **both** Taylor polynomials **and** midpoint rule. Start choosing **either** precise evaluation of the Taylor polynomial **or** using midpoint rule on *the original function*. From 1000x1000 problem you come to 1000000x1 problem, much better results with the same resources – Jan Stránský Sep 11 '20 at 13:48
  • 1
    I am doing that simply because it's for a school project, in which both methods must be represented. If that wasn't the case, I completely agree with you, either using Taylor expansion or the midpoint rule on its own would be much more favorable. – Nikolai Sep 11 '20 at 19:29