I have a Python program for calculating the integral of a function in just one point. But this is simply not effective as I want to calculate more x values at the same time, not just one value. Anyone have any idea?
from scitools.std import *
def trapezoidal(f,a,x,n):
h = (x-a)/float(n)
I = 0.5*f(a)
for i in iseq(1, n-1):
I += f(a+i*h)
I += 0.5*f(x)
I *= h
return I
class Integral:
def __init__(self, f, a, n=100):
self.f, self.a, self.n = f,a,n
def __call__(self,x):
return trapezoidal(self.f,self.a,x,self.n)
Related
So I have been trying to create an integrate class for an assignment and while I have gotten a simple skeletal structure for the functions within said class, I keep on getting a None result, which really bugs me. The code that I have written down though is written below.
What do I do to make this code work?
import math
class Integrator():
def __init__(self, xMin, xMax, N):
x = []
self.xMin = min(x)
self.xMax = max(x)
self.N = N
def I(self, x):
(x**2)*np.exp(-x)*np.sin(x)
def integrate(self):
y = list(np.arange(self.xMin, self.xMax, self.N))
tot = 0
i = 0
while i < self.xMax:
tot += y [i]
i += self.N
np.sum(tot)*(self.xMax-self.xMin)/self.N
examp = Integrator(1,3,20000)
examp.integrate()
You're missing a return statement on the integrate and I methods. That is why they both exclusively return None.
Beyond that, there are some other issues. For example, the min and max statements here will not work. These operators do not work on an empty sequence (which is what x is). Perhaps you meant self.xMin = xMin?
class Integrator():
def __init__(self, xMin, xMax, N):
x = []
self.xMin = min(x)
self.xMax = max(x)
Beyond that, there are some curiosities with the integrate method. For example, the while loop will only do one iteration, because i < self.xMax (which is 3 in your example), but every iteration i gets incremented by self.N (which is 20000 in your example).
np.sum(tot) is also illogical, as that only works when tot is "array-like", but tot is just a float (or int). No need to sum one of those.
Then, list(np.arange(self.xMin, self.xMax, self.N)) likely does not do what you're expecting. np.arange is given a start, stop and step parameter. That means that it starts at 1 (self.xMin), then sets a step of 20000 (self.N), and then because that is larger than stop of 3 (self.xMax), it will not include that one. So, y = [1]. Maybe you'd want y = list(np.arange(self.xMin, self.xMax, 1 / self.N)), so that the step is such that y has a length of 40000.
That said, I have no idea what you're expecting to get returned from this method. Perhaps it's along the lines of this though:
import math
import numpy as np
class Integrator():
def __init__(self, xMin, xMax, N):
x = []
self.xMin = xMin
self.xMax = xMax
self.N = N
def I(self, x):
return (x**2)*np.exp(-x)*np.sin(x)
def integrate(self):
y = list(np.arange(self.xMin, self.xMax, 1 / self.N))
tot = 0
i = 0
while i < len(y):
tot += y[i]
i += 1
return tot*(self.xMax-self.xMin)/self.N
examp = Integrator(1,3,20000)
print(examp.integrate())
Which returns 7.999900000008443.
I am developing a simulation of the integration of montecarlo (dx) and I find myself wondering which is the best way to determine the exact number of samples (N) in the Monte Carlo method to approximate the solution to a definite integral.
This is a simple code of implementation:
import math
import random
class Montecarlo:
def __init__ (self):
print ("Inicializa..")
def fy(self, ri, a, b):
res = math.pow((b-a)*ri+a, 2.0)+math.sqrt((b-a)*ri+a)
return res
def integral (self, a, b, N):
suma = 0.0
ri = 0.0
for i in range (N):
ri = random.random()
suma+=self.fy(ri,a,b)
res=((b-a)/N)*suma
return res
if __name__ == "__main__":
monte = Montecarlo()
res = monte.integral(10.0,27.0,N)
print("Res: ", res)
Where N must be a value that allows to approximate the real result of the integral
Win Monte Carlo, you could compute statistical error (stddev) of the simulation. It goes down as 1/sqrt(N). You could set your goal - say, make error below 2% - and easily compute now many samples (N) you need.
I modified your code and added calculation of second momentum, sigma and simulation error
import math
import random
class Montecarlo:
def __init__(self):
print ("Inicializa..")
def fy(self, ri, a, b):
res = math.pow((b-a)*ri+a, 2.0) + math.sqrt((b-a)*ri+a)
return res
def integral (self, a, b, N):
sum = 0.0
var = 0.0
for i in range(N):
ri = random.random()
v = self.fy(ri, a, b)
sum += v
var += v*v
sum /= float(N)
var /= float(N)
sigma = ( var - sum*sum ) * float(N)/float(N-1)
error = sigma / math.sqrt(N)
return ((b-a) * sum, (b-a)*error)
if __name__ == "__main__":
N = 100000
monte = Montecarlo()
res, err = monte.integral(10.0, 27.0, N)
print("Res: {0}, Err: {1}".format(res, err))
I have this 2-dimensional integral with dependent limits. The function can be defined in Python as
def func(gamma, u2, u3):
return (1-1/(1+gamma-u3-u2))*(1/(1+u2)**2)*(1/(1+u3)**2)
where the limits of u3 is from 0 to gamma (a positive real number), and the limits of u2 is from 0 to gamma-u3.
How can I implement this using scipy.integrate.nquad? I tried to read the documentation, but it was not easy to follow, especially I am relatively new to Python.
Extension: I would like to implement a numerical integration for an arbiraty K, where the integrand in this case is given by (1-1/(1+gamma-uk-....-u2))*(1/(1+uK)**2)*...*(1/(1+u2)**2). I wrote the function that takes a dynamic number of arguments as follows:
def integrand(gamma, *args):
'''
inputs:
- gamma
- *args = (uK, ..., u2)
Output:
- (1-1/(1+gamma-uk-....-u2))*(1/(1+uK)**2)*...*(1/(1+u2)**2)
'''
L = len(args)
for ll in range(0, L):
gamma -= args[ll]
func = 1-1/(1+gamma)
for ll in range(0, L):
func *= 1/((1+args[ll])**2)
return func
However, I am not sure how to do the same for the ranges, where I will have one function for the ranges, where uK ranges from 0 to gamma, u_{K-1} ranges from 0 to gamma-uK, ...., u2 ranges from 0 to gamma-uK-...-u2.
Here is a simpler method using scipy.integrate.dblquad instead of nquad:
Return the double (definite) integral of func(y, x) from x = a..b and
y = gfun(x)..hfun(x).
from scipy.integrate import dblquad
def func(u2, u3, gamma):
return (1-1/(1+gamma-u3-u2))*(1/(1+u2)**2)*(1/(1+u3)**2)
gamma = 10
def gfun(u3):
return 0
def hfun(u3):
return gamma-u3
dblquad(func, 0, gamma, gfun, hfun, args=(gamma,))
It seems that gfun and hfun do not accept the extra arguments, so gamma has to be a global variable.
Using nquad, after many trial and error:
from scipy.integrate import nquad
def func(u2, u3, gamma):
return (1-1/(1+gamma-u3-u2))*(1/(1+u2)**2)*(1/(1+u3)**2)
def range_u3(gamma):
return (0, gamma)
def range_u2(u3, gamma):
return (0, gamma-u3)
gamma = 10
nquad(func, [range_u2, range_u3], args=(gamma,) )
Useful quote from the source code of tplquad:
# nquad will hand (y, x, t0, ...) to ranges0
# nquad will hand (x, t0, ...) to ranges1
And from the nquad documentation, the order of the variables is reversed (same for dblquad):
Integration is carried out in order. That is, integration over x0 is the innermost integral, and xn is the outermost
Generic case with k nested integrations:
from scipy.integrate import nquad
import numpy as np
def func(*args):
gamma = args[-1]
var = np.array(args[:-1])
return (1-1/(1+gamma-np.sum(var)))*np.prod(((1+var)**-2))
def range_func(*args):
gamma = args[-1]
return (0, gamma-sum(args[:-1]))
gamma, k = 10, 2
nquad(func, [range_func]*k, args=(gamma,) )
I wrote the following code. It is a ODE which has a parameter in it as another ODE.
As we can see M(m0,z,b,c) in used in another ODE which itself is a ODE function. the code is very slow, Could anyone give me a suggestion how to improve it?
import numpy as np
from scipy.integrate import odeint
def model(m,z,c,b):
dmdt = ((c**2-m)/(1+z))*(6-9*(m/c**2)+3*b*(m+(m**2)))
return dmdt
def M(m0,z,c,b):
m = odeint(model,m0,[0,z], args= (c, b))
mm=m[-1,0]
return mm
def model1(H ,z,m0,c,b):
c = 0.6
b=0.035
dHdt = (H/(1+z))*(6-9*(M(m0,z,c,b)/c**2)+3*b*(M(m0,z,c,b)+(M(m0,z,c,b)**2)))
return dHdt
def model2(H0,z,m0,c,b):
H = odeint(model1,H0,[0,z], args=(m0,c,b))
HH=H[-1,0]
return HH
print(model2(70,1,0.75,0.69,0.035))
You can solve a coupled system as a coupled system.
def model(U,z,c,b):
M, H = U
dMdt = ((c**2-M)/(1+z))*(6-9*(M/c**2)+3*b*(M+M**2))
dHdt = (H /(1+z))*(6-9*(M/c**2)+3*b*(M+M**2))
return [dMdt, dHdt]
def solution(H0,z,m0,c,b):
U = odeint(model,[m0,H0],[0,z], args=(c,b))[-1]
M, H = U
return H
print(solution(70,1,0.75,0.69,0.035))
which rapidly returns 0.107569653042 while your code with the modifications
def model1(H, z, m0, c, b):
mm = M(m0,z,c,b)
dHdt = (H/(1+z))*(6-9*(mm/c**2)+3*b*(mm+(mm)**2)))
return dHdt
returns the similar 0.107569746892 somewhat slower. These 6 digits of coincidence are consistent with the default error tolerances of 1e-6.
To get results with higher accuracy set the control parameters for the error tolerances atol, rtol.
For further reduction in operations do
def model(U,z,c,b):
M, H = U
factor = (6-9*M/c**2+3*b*(M+M**2))/(1+z)
return [(c**2-M)*factor, H*factor]
If your task is really massive, use a compiled programming language for fast mass number crunching.
I have a fully functional code with three functions each of which returns outputs of it own. My task is to create one function which can call all the other functions and return the outputs of all the functions. how do I do that?
My code is as follows:
def func(x, y):
return x * x + y * y, x * y
def generate_data(size):
nx = 5
mx = 0.5
mux, sigmax = nx, mx/3
ny = 3
my = 0.9
muy, sigmay = ny, my/3
result1=[]
result2=[]
for i in range(size):
result = func(random.gauss(mux, sigmax), random.gauss(muy, sigmay))
result1.append(result[0])
result2.append(result[1])
return result1, result2
def analysis(ls):
avg = np.mean(ls)
std = np.std(ls)
pre = 3 * std
return avg, std, pre
say, for eg: I need to create a function
def My_func()
and this function should have the other functions and returns its outputs
Just as you have done in each of your existing functions, you can return multiple results in one line.
def My_func(x, y, size, ls):
return analysis(ls), generate_data(size), func(x,y)
You can return them at once.Like this:
return analysis(x,y), generate_data(size), func(ls)
To receive the value, you have to unpack
Valanalysis,Valgenerate_data,valfunc=My_func(x, y,size,ls)