Using nquad for a double integral - python

Having a problem here. Here's my code so far:
from scipy import integrate
import math
import numpy as np
a = 0.250
s02 = 214.0
a_s = 0.0163
def integrand(r, R, s02, a_s, a):
return 2.0 * r * (r/a)**(-0.1) * (1.0 + (r**2/a**2))**(-2.45)\\
*(math.sqrt(r**2 - R**2))**(-1.0) * (a_s/(1 + (R-0.0283)**2/a_s**2 ))
def bounds_R(s02, a_s, a):
return [0, np.inf]
def bounds_r(R, s02, a_s, a):
return [R, np.inf]
result = integrate.nquad(integrand, [bounds_r(R, s02, a_s, a), bounds_R(s02, a_s, a)])
a, s02 and a_s are constants. I need to perform the first integral over r, and then the second integral over R. The problem I think is the fact that R appears in the limits for the first integral (something called an Abel transform). Tried a few things and every time getting an error that there are either too few arguments in the boundary functions or too little.
Please help!

If you write integrate.nquad(integrand, [bounds_r(R, s02, a_s, a), bounds_R(s02, a_s, a)]), python is expecting you to affect a value to R. But you didn't because integration is carried out over R.
This syntax should work :
result = integrate.nquad(integrand, [bounds_r, bounds_R], args=(s02,a_s,a))
Take a look to the second example in the documentation of integrate.nquad.

Related

how to optimize the minimization of a vector function in python?

I have an issue: I'm trying to find the minimum of a function which depends on several parameters that I'd like to change as well. let's take as a simplified example:
import numpy as np
import scipy.optimize as opt
def f(x, a, b, c):
f = a * x**2 + b * x + c
return f
I'd like to find the x which minimizes the function for different set of values of a, b, c, let's say for
a = [-1, 0, 1]
b = [0, 1, 2]
c = [0, 1]
ATM I have three nested loops and a minimization:
for p1 in a:
for p2 in b:
for p3 in c:
y = opt.minimize(f, x0=[0, ], args=(p1, p2, p3, ))
print(y)
which is really slow for the calculation I'm doing, but I haven't found any better so far. So, does anyone know a way or a package that would allow me to improve the efficiency?
You could use a combination of different techniques to improve the efficiency of your script:
Use itertools.product to generate every possible combination in the list a, b, c
Use multiprocessingto execute the minimizations in parallel.
Other than this, i can't think of a way to optimize the efficiency of the code. As was pointed out in the comment, the constant value c has no influence on the minimization. But i'm sure the quadratic function is just an example.
I took the code of the multiprocessing part from here.
Here's the working code.
import numpy as np
import scipy.optimize as opt
import itertools
from multiprocessing import Pool
def f(x, a, b, c):
f = a * x**2 + b * x + c
return f
def mini(args):
res = opt.minimize(f, x0=np.array([0]), args=args)
return res.x
if __name__=="__main__":
a = np.linspace(-1,2,100)
b = np.linspace(0,2,100)
c = [0, 1]
args = list(itertools.product(a,b,c))
print("Number of combos:" + str(len(args)))
p = Pool(4)
import time
t0 = time.time()
res = p.map(mini, args)
print(time.time()-t0)
Even these 20000 combinations only need 5,28 seconds on my average laptop.
scipy.optimize.newton can do this.

Plotting Fourier Series coefficients in Python using Simpson's Rule

I want to 1. express Simpson's Rule as a general function for integration in python and 2. use it to compute and plot the Fourier Series coefficients of the function .
I've stolen and adapted this code for Simpson's Rule, which seems to work fine for integrating simple functions such as ,
or
Given period , the Fourier Series coefficients are computed as:
where k = 1,2,3,...
I am having difficulty figuring out how to express . I'm aware that since this function is odd, but I would like to be able to compute it in general for other functions.
Here's my attempt so far:
import matplotlib.pyplot as plt
from numpy import *
def f(t):
k = 1
for k in range(1,10000): #to give some representation of k's span
k += 1
return sin(t)*sin(k*t)
def trapezoid(f, a, b, n):
h = float(b - a) / n
s = 0.0
s += f(a)/2.0
for j in range(1, n):
s += f(a + j*h)
s += f(b)/2.0
return s * h
print trapezoid(f, 0, 2*pi, 100)
This doesn't give the correct answer of 0 at all since it increases as k increases and I'm sure I'm approaching it with tunnel vision in terms of the for loop. My difficulty in particular is with stating the function so that k is read as k = 1,2,3,...
The problem I've been given unfortunately doesn't specify what the coefficients are to be plotted against, but I am assuming it's meant to be against k.
Here's one way to do it, if you want to run your own integration or fourier coefficient determination instead of using numpy or scipy's built in methods:
import numpy as np
def integrate(f, a, b, n):
t = np.linspace(a, b, n)
return (b - a) * np.sum(f(t)) / n
def a_k(f, k):
def ker(t): return f(t) * np.cos(k * t)
return integrate(ker, 0, 2*np.pi, 2**10+1) / np.pi
def b_k(f, k):
def ker(t): return f(t) * np.sin(k * t)
return integrate(ker, 0, 2*np.pi, 2**10+1) / np.pi
print(b_k(np.sin, 0))
This gives the result
0.0
On a side note, trapezoid integration is not very useful for uniform time intervals. But if you desire:
def trap_integrate(f, a, b, n):
t = np.linspace(a, b, n)
f_t = f(t)
dt = t[1:] - t[:-1]
f_ab = f_t[:-1] + f_t[1:]
return 0.5 * np.sum(dt * f_ab)
There's also np.trapz if you want to use pre-builtin functionality. Similarly, there's also scipy.integrate.trapz

Finding unknowns in function from known output using Scipy/Python

I have the following python function required inputs a and b.
def interimfunc(x,y,z):
#this is a dummy function - not a part of the actual question but included for completeness.
#the actual function involves some statistical treatment - but that is not a problem here.
sol = x*y+z
return sol
def finalfunc(a, b):
interimsol1 = interimfunc(0.4,a,b)
interimsol2 = interimfunc(0.8,a,b)
finalsol = interimsol1/interimsol2
return finalsol
if finalsol is a known value.
How do I find out the unknowns "a" and "b" by solving non-linear system of equations??
===
I got 4 down-votes after posting this. I am a mechanical engineer and learning computer science. I did try researching on the internet but need to refine my search - hence I asked a question to experts here.
===
In addition to above equations - there is one more information:
interimsol2 = interimfunc(0.8,a,b)
where interimsol2 = 10 #i.e. known value
How do we inclde this new information in our unknown finding?
===
Actual problem as requested below by #SergeyIvanov
def func(mu, sigma):
tenpercent = st.norm.ppf(2, mu, sigma)
ninetypercent = st.norm.ppf(2, mu, sigma)
rfs = tenpercent/ninetypercent
return rfs
I think you should solve a system of nonlinear equations. This code should solve your problem in case of two equations for two known solutions (of course you can extend it):
from scipy.optimize import fsolve
known_values = [3,5]
def interimfunc(x,y,z):
sol = x*y+z
return sol
def finalfunc(a, b):
interimsol1 = interimfunc(0.4,a,b)
interimsol2 = interimfunc(0.8,a,b)
finalsol = interimsol1/interimsol2
return finalsol
def equations(p):
a, b = p
return (finalfunc(a,b) - known_values[0], # finalfunc(a,b) == solution1
finalfunc(a,b) - known_values[1]) # finalfunc(a,b) == solution2
a, b = fsolve(equations, (1, 1))# solution
print(a,b)
# -6192.07497308 5779.26987919
print(equations((a, b)))
# (1.0000003476651482, -0.99999965233485177) <-- bad convergence beacause there is no free paremeter in finalfunc.
But it works only with equal known_values, that is pointless (solution will be a random combination of a and b). The problem is that you should have something to distinguish two equations finalfunc (e.g. additional parameter), because you can get diffrent solutions only with different arguments. So finally you should have something like this:
from scipy.optimize import fsolve
def interimfunc(x,y,z):
sol = x*y+z
return sol
def finalfunc(a, b, c ):
interimsol1 = interimfunc(0.4,a,b) + c
interimsol2 = interimfunc(0.8,a,b) + c
finalsol = interimsol1/interimsol2
return finalsol
known_values = [0.8260869565217391,0.8333333333333334]
def equations(p):
a, b = p
return (finalfunc(a,b,0) - known_values[0], # finalfunc(a,b,c) == solution1
finalfunc(a,b,1) - known_values[1]) # finalfunc(a,b,c) == solution2
a, b = fsolve(equations, (1, 1))# solution
print(a,b)
print(equations((a, b)))
# 10.0 15.0 <-- correct values
# (4.4408920985006262e-16, 2.2204460492503131e-16) <-- good convergence
For last example:
from scipy.optimize import fsolve
import scipy.stats as st
def equations(p):
mu, sigma = p
tenpercent = st.norm.ppf(2, mu, sigma)
ninetypercent = st.norm.ppf(2, mu, sigma)
return (ninetypercent - 500,
tenpercent / ninetypercent - 1.0)
mu, sigma = fsolve(equations,x0=(100, 10))# solution
print("mu, sigma:",mu, sigma)
print(equations((mu, sigma)))
The problem here is that ppf can generate nan and ruin an optimization process. So guess values should be proposed very carefully.

Improving accuracy in scipy.optimize.fsolve with equations involving integration

I'm trying to solve an integral equation using the following code (irrelevant parts removed):
def _pdf(self, a, b, c, t):
pdf = some_pdf(a,b,c,t)
return pdf
def _result(self, a, b, c, flag):
return fsolve(lambda t: flag - 1 + quad(lambda tau: self._pdf(a, b, c, tau), 0, t)[0], x0)[0]
Which takes a probability density function and finds a result tau such that the integral of pdf from tau to infinity is equal to flag. Note that x0 is a (float) estimate of the root defined elsewhere in the script. Also note that flag is an extremely small number, on the order of 1e-9.
In my application fsolve only successfully finds a root about 50% of the time. It often just returns x0, significantly biasing my results. There is no closed form for the integral of pdf, so I am forced to integrate numerically and feel that this might be introducing some inaccuracy?
EDIT:
This has since been solved using a method other than that described below, but I'd like to get quadpy to work and see if the results improve at all. The specific code I'm trying to get to work is as follows:
import quadpy
import numpy as np
from scipy.optimize import *
from scipy.special import gammaln, kv, gammaincinv, gamma
from scipy.integrate import quad, simps
l = 226.02453163
mu = 0.00212571582056
nu = 4.86569872444
flag = 2.5e-09
estimate = 3 * mu
def pdf(l, mu, nu, t):
return np.exp(np.log(2) + (l + nu - 1 + 1) / 2 * np.log(l * nu / mu) + (l + nu - 1 - 1) / 2 * np.log(t) + np.log(
kv(nu - l, 2 * np.sqrt(l * nu / mu * t))) - gammaln(l) - gammaln(nu))
def tail_cdf(l, mu, nu, tau):
i, error = quadpy.line_segment.adaptive_integrate(
lambda t: pdf(l, mu, nu, t), [tau, 10000], 1.0e-10
)
return i
result = fsolve(lambda tau: flag - tail_cdf(l, mu, nu, tau[0]), estimate)
When I run this I get an assertion error from assert all(lengths > minimum_interval_length). I'm not quite sure of how to remedy this; any help would be very much appreciated!
As an example, I tried 1 / x for the integration between 1 and alpha to retrieve the target integral 2.0. This
import quadpy
from scipy.optimize import fsolve
def f(alpha):
beta, _ = quadpy.quad(lambda x: 1.0/x, 1, alpha)
return beta
target = 2.0
res = fsolve(lambda alpha: target - f(alpha), x0=2.0)
print(res)
correctly returns 7.38905611.
The failing quadpy assertion
assert all(lengths > minimum_interval_length)
you're getting means that the adaptive integration hit its limit: Either relax your tolerance a bit, or decrease the minimum_interval_length (see here).

Fitting a variable Sinc function in python

I would like to fit a sinc function to a bunch of datalines.
Using a gauss the fit itself does work but the data does not seem to be sufficiently gaussian, so I figured I could just switch to sinc..
I just tried to put together a short piece of self running code but realized, that I probably do not fully understand, how arrays are handled if handed over to a function, which could be part of the reason, why I get error messages calling my program
So my code currently looks as follows:
from numpy import exp
from scipy.optimize import curve_fit
from math import sin, pi
def gauss(x,*p):
print(p)
A, mu, sigma = p
return A*exp(-1*(x[:]-mu)*(x[:]-mu)/sigma/sigma)
def sincSquare_mod(x,*p):
A, mu, sigma = p
return A * (sin(pi*(x[:]-mu)*sigma) / (pi*(x[:]-mu)*sigma))**2
p0 = [1., 30., 5.]
xpos = range(100)
fitdata = gauss(xpos,p0)
p1, var_matrix = curve_fit(sincSquare_mod, xpos, fitdata, p0)
What I get is:
Traceback (most recent call last):
File "orthogonal_fit_test.py", line 18, in <module>
fitdata = gauss(xpos,p0)
File "orthogonal_fit_test.py", line 7, in gauss
A, mu, sigma = p
ValueError: need more than 1 value to unpack
From my understanding p is not handed over correctly, which is odd, because it is in my actual code. I then get a similar message from the sincSquare function, when fitted, which could probably be the same type of error. I am fairly new to the star operator, so there might be a glitch hidden...
Anybody some ideas? :)
Thanks!
You need to make three changes,
def gauss(x, A, mu, sigma):
return A*exp(-1*(x[:]-mu)*(x[:]-mu)/sigma/sigma)
def sincSquare_mod(x, A, mu, sigma):
x=np.array(x)
return A * (np.sin(pi*(x[:]-mu)*sigma) / (pi*(x[:]-mu)*sigma))**2
fitdata = gauss(xpos,*p0)
1, See Documentation
2, replace sin by the numpy version for array broadcasting
3, straight forward right? :P
Note, i think you are looking for p1, var_matrix = curve_fit(gauss,... rather than the one in the OP, which appears do not have a solution.
Also worth noting is that you will get rounding errors as x*Pi gets close to zero that might get magnified. You can approximate as demonstrated below for better results (VB.NET, sorry):
Private Function sinc(x As Double) As Double
x = (x * Math.PI)
'The Taylor Series expansion of Sin(x)/x is used to limit rounding errors for small values of x
If x < 0.01 And x > -0.01 Then
Return 1.0 - x ^ 2 / 6.0 + x ^ 4 / 120.0
End If
Return Math.Sin(x) / x
End Function
http://www.wolframalpha.com/input/?i=taylor+series+sin+%28x%29+%2F+x&dataset=&equal=Submit

Categories

Resources