Trapezoidal approximation error plotting in python - python-3.x

Im trying to code a function that plots the error of the composite trapezoidal rule against the step size.
Obviously this doesn't look to good since i'm just starting to learn these things.
Anyhow i managed to get the plot and everything, but i'm supposed to get a plot with slope 2, so i am in need of help to figure out where i did go wrong.
from scipy import *
from pylab import *
from matplotlib import *
def f(x): #define function to integrate
return exp(x)
a=int(input("Integrate from? ")) #input for a
b=int(input("to? ")) #inpput for b
n=1
def ctrapezoidal(f,a,b,n): #define the function ctrapezoidal
h=(b-a)/n #assign h
s=0 #clear sum1-value
for i in range(n): #create the sum of the function
s+=f(a+((i)/n)*(b-a)) #iterate th sum
I=(h/2)*(f(a)+f(b))+h*s #the function + the sum
return (I, h) #returns the approximation of the integral
val=[] #start list
stepsize=[]
error=[]
while len(val)<=2 or abs(val[-1]-val[-2])>1e-2:
I, h=ctrapezoidal(f,a,b,n)
val.append(I)
stepsize.append(h)
n+=1
for i in range(len(val)):
error.append(abs(val[i]-(e**b-e**a)))
error=np.array(error)
stepsize=np.array(stepsize)
plt.loglog(stepsize, error, basex=10, basey=10)
plt.grid(True,which="both",ls="steps")
plt.ylabel('error')
plt.xlabel('h')

Related

Easyviz and scitools.std still works on python3? There is an alternative to making films from a sequence of images?

I am studying the book 'A Primer on Scientific Programming with Python 2nd' by Hans Petter Langtangen. The book uses python2 but I am applying it in python3. The scotools.std library is widely used in the book, but I cannot import or install it in python3. Is there an alternative to scitools.std that works for python3? (This may solve my difficulty in following the book.)
Specifically in this question I'm looking for an alternative to Easyviz, because I can't make a movie with the graph of the Gaussian function by modifying the parameter s as desired in the question.
The python2 code presented in the book is:
from scitools.std import *
import time
def f(x, m, s):
return (1.0/(sqrt(2*pi)*s))*exp(-0.5*((x-m)/s)**2)
m = 0
s_start = 2
s_stop = 0.2
s_values = linspace(s_start,s_stop, 30)
x = linspace(m - 3*s_start, m + 3*s_start, 1000)
# f is max for x=m; smaller s gives larger max value
max_f = f(m, m s_stop)
# Show the movie on the screen
# and make hardcopies of frames simultaneously.
counter = 0
for s in s_values:
y = f(x, m, s)
plot(x, y, axis=[x[0], x[-1], -0.1, max_f],
xlabel='x', ylabel='f', legend='s=%4.2f' % s,
savefig='tmp%04d.png' % counter)
counter += 1
#time.sleep(0.2)
# Make movie file the simplest possible way:
movie('tmp*.png')
My incomplete version in python3 is:
import time
import numpy as np
import matplotlib.pyplot as plt
def f(x, m, s):
return (1.0/(np.sqrt(2*np.pi)*s))*np.exp(-0.5*((x-m)/s)**2)
m = 0
s_start = 2
s_stop = 0.2
s_values = np.linspace(s_start, s_stop, 30)
x = np.linspace(m - 3*s_start, m + 3*s_start, 1000)
# f is max for x=m; smaller s gives larger max value
max_f = f(m, m, s_stop)
# Show the movie on the screen
# and make hardcopies of frames simultaneosly.
counter = 0
for s in s_values:
y = f(x, m, s)
plt.plot(x, y)
plt.xlim(x[0], x[-1])
plt.ylim(-0.1, max_f + 0.1)
plt.xlabel('x')
plt.ylabel('f')
plt.legend('s=%4.2f' % s)
plt.savefig('tmp%04d.png' % counter)
counter += 1
#time.sleep(0.2)
plt.show()
This produces the 30 images correctly, but it does not go ahead and produces the movie.
*Note that I used plt.show () and I have to close 30 windows, if I don't use each generated file it shows the accumulated curves in the same graph.
So I see three ways to solve my problem:
1) Being able to correctly install and import scitools.std (this would be excellent, because the problem goes through the whole book!);
2) Getting an alternative to the scitools.std and Easyviz module;
3) Following the path I adopted in my incomplete version of the code, that is, replacing the command movie ('tmp * .png') presented by the book with something that works well in my code.
Yes, there is a module called scitools3.
You can install by:
pip install scitools3
and reboot your PC.
read more at https://pypi.org/project/scitools3/
/masa

Numpy: division by zero error, but mathematically function is apparently defined

I'm testing out some functions to fit with data, and one of them (in 2-D) is
f(x) = (1/(1-x)) / (1 + 1/(1-x))
Which, according to Wolfram and the Google plotters, gives you the result
f(1) = 1
I've tried to get this to work without hard coding the case
if x == 1:
return 1
but I end up with a nan and a RunTimeWarning informing me that I have indeed divided by zero.
import numpy as np
def f(x):
return 1/(1-x) / (1 + 1/(1-x))
x_range = np.linspace(0, 1, 50)
y = f(x_range)
print(y)
Is there a more elegant solution than to simply introduce a hard-coded if?
Is there a reason to keep it in this form, you can simplify it to:
def f(x):
return 1/(2-x)
Wolfram and Google probably to some sort of algebraic simplification too.
Just simplify the equation for f(x) = (1/(1-x)) / (1 + 1/(1-x)). The simplified equation will be (1/(2-x)). Now update the program as:
import numpy as np
def f(x):
return 1/(2-x)
x_range = np.linspace(0, 1, 50)
y = f(x_range)
print(y)
output:
[0.5 0.50515464 0.51041667 0.51578947 0.5212766 0.52688172
0.5326087 0.53846154 0.54444444 0.5505618 0.55681818 0.56321839
0.56976744 0.57647059 0.58333333 0.59036145 0.59756098 0.60493827
0.6125 0.62025316 0.62820513 0.63636364 0.64473684 0.65333333
0.66216216 0.67123288 0.68055556 0.69014085 0.7 0.71014493
0.72058824 0.73134328 0.74242424 0.75384615 0.765625 0.77777778
0.79032258 0.80327869 0.81666667 0.83050847 0.84482759 0.85964912
0.875 0.89090909 0.90740741 0.9245283 0.94230769 0.96078431
0.98 1. ]

Python, scipy - How to fit a curve using a piecewise function with a conditional parameter that also needs to be calculated?

As the title suggests, I'm trying to fit a piecewise equation to a large data set. The equations I would like to fit to my data are as follows:
y(x) = b, when x < c
else:
y(x) = b + exp(a(x-c)) - 1, when x >= c
There are multiple answers to how such an issue can be addressed, but as a Python beginner I can't figure out how to apply them to my problem:
Curve fit with a piecewise function?
Conditional curve fit with scipy?
The problem is that all variables (a,b and c) have to be calculated by the fitting algorithm.
Thank you for your help!
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# Reduced Dataset
y = np.array([23.032, 21.765, 20.525, 21.856, 21.592, 20.754, 20.345, 20.534,
23.502, 21.725, 20.126, 21.381, 20.217, 21.553, 21.176, 20.976,
20.723, 20.401, 22.898, 22.02 , 21.09 , 22.543, 22.584, 22.799,
20.623, 20.529, 20.921, 22.505, 22.793, 20.845, 20.584, 22.026,
20.621, 23.316, 22.748, 20.253, 21.218, 23.422, 23.79 , 21.371,
24.318, 22.484, 24.775, 23.773, 25.623, 23.204, 25.729, 26.861,
27.268, 27.436, 29.471, 31.836, 34.034, 34.057, 35.674, 41.512,
48.249])
x = np.array([3756., 3759., 3762., 3765., 3768., 3771., 3774., 3777., 3780.,
3783., 3786., 3789., 3792., 3795., 3798., 3801., 3804., 3807.,
3810., 3813., 3816., 3819., 3822., 3825., 3828., 3831., 3834.,
3837., 3840., 3843., 3846., 3849., 3852., 3855., 3858., 3861.,
3864., 3867., 3870., 3873., 3876., 3879., 3882., 3885., 3888.,
3891., 3894., 3897., 3900., 3903., 3906., 3909., 3912., 3915.,
3918., 3921., 3924.])
# Simple exponential function without conditions (works so far)
def exponential_fit(x,a,b,c):
return b + np.exp(a*(x-c))
popt, pcov = curve_fit(exponential_fit, x, y, p0 = [0.1, 20,3800])
plt.plot(x, y, 'bo')
plt.plot(x, exponential_fit(x, *popt), 'r-')
plt.show()
You should change your function to something like
def exponential_fit(x, a, b, c):
if x >= c:
return b + np.exp(a*(x-c))-1
else:
return b
Edit: As chaosink pointed out in the comments, this approach no longer works as the the above function assumes that x is a scalar. However, curve_fit evaluates the function for array-like x. Consequently, one should use vectorised operations instead, see here for more details. To do so, one can either use
def exponential_fit(x, a, b, c):
return np.where(x >= c, b + np.exp(a*(x-c))-1, b)
or chaosink's suggestion in the comments:
def exponential_fit(x, a, b, c):
mask = (x >= c)
return mask * (b + np.exp(a*(x-c)) - 1) + ~mask * b
Both give:

Python 3.x finding derivatives

I'm trying to make a derivative calculator.
Here is my code.
from sympy import symbols, Limit, S
x, h = symbols('x, h')
def g(x):
def f(x):
y = input("Function:")
return eval(y, {'__builtins__': {}}, {'x': x})
return Limit((f(x+h)-f(x))/h , h, S.Zero).doit()
print (g(x))
But when I run the code, I have to put the "Functions" twice. It seems that it happens because there are two f's ( f(x+h) and f(x) ) when g(x) is defined.
How can I fix it? I mean, I don't want to put my function two times...
Anyone can help me?

Program is written but cant get it to concatenate

This program takes 4 points on a graph and puts them into a Lagrange polynomial. I got my terms to output correctly but I need to concatenate the 4 terms into 1 line of code. No matter where I seem to try to concatenate, it keeps messing up the loops and therefore messing up my terms. I'm sure there is an easier way to do this, but I have to use strings and concatenation for my assignment. Any help would be appreciated. Thanks.
import string
from math import *
def main():
n=4
abscissa=[-5,-2,3,7]
ordinate=[4,-6,8,1]
for j in range(n):
LP=str(ordinate[j])
denom="1"
for k in range(n):
if k!=j:
denom= denom+"*("+str(abscissa[j])+"-"+str(abscissa[k])+")"
LP=LP+"*(x-"+str(abscissa[k])+")"
LP=LP+'/'+denom
print(LP)
main()
Collect the terms, and join them:
import string
from math import *
def main():
n=4
abscissa=[-5,-2,3,7]
ordinate=[4,-6,8,1]
result = ''
for j,y in enumerate(ordinate):
if j!=0:
result += '+'
LP=str(y)
denom="1"
for k,x in enumerate(abscissa):
if k!=j:
denom += '*({}-{})'.format(abscissa[j],x)
LP += '*(x-{})'.format(x)
LP += '/' + denom
result += LP
print(result)
main()

Resources