Nested integral in Python - python

I have an M-dimensional integral where the outer limits over x_M are [0, y], the next limits over x_{M-1} are [0, max(x_M, y-x_M)], .... and the inner integral is over x_1 with limits [0, max(x_2, y-x_M-...-x_2)].
The function/integrand is
(K!/(K-M)!)*(1/(x_1+1)^2)*....*(1/(x_{M-1}+1)^2)*(1/(x_M+1)^{K-M+2})
where K and M are integers such that K >= M >= 1, and K!=K*(K-1)*...*2*1 is K factorial.
How can I do this in Python using scipy.integrate.nquad? I had a similar problem here, but don't know how to extend the code there to my case here.
The LaTeX version of the integral:
My attempt (but the code isn't working. It doesn't give a result between 0 and 1)
K=4
M=2
du = 0.01
#For m=M
def F(u):
return 1/(1+u)**(K-M+2)
#For m=1,2,...,M-1
def f(u):
return 1/((1+u))**2
#Recursive function to evaluate the integral
def G(h, m, prev_lim):
#print(f'h is {h}, and k is {k}')
if m == M:
res = F(h)
else:
res = 0
u = prev_lim
while u < h:
res += G(h-u, m+1, u)*f(u)*du
u += du
return (math.factorial(K)/math.factorial(K-M))*res
print(G(2, 1, 0))

Related

Can I specify a function in python this way or will my results be corrupted

I am trying to bring something from an R package by Lotze & Loecher into python as all of the rest of the project is.
Here is the python code:
def dbeta(x,shape1,shape2):
from scipy.stats import beta
result=beta.pdf(x=x,a=shape1,b=shape2,loc=0,scale=1)
return result
def pbeta(q,shape1,shape2):
from scipy.stats import beta
result=beta.cdf(x=q,a=shape1,b=shape2,loc=0,scale=1)
return result
def combinations(array, tuple_length, prev_array=[]):
if len(prev_array) == tuple_length:
return [prev_array]
combs = []
for f, val in enumerate(array):
prev_array_extended = prev_array.copy()
prev_array_extended.append(val)
combs += combinations(array[f+1:], tuple_length, prev_array_extended)
return combs
After defining these functions here I have the problem with too many iterations in the function I think:
from scipy.integrate import quad
def best_binominal_bandit(x, n, alpha=1, beta=1):
ans = []
# x = vector of number of successes
# n = vector of number of tries
k = len(x)
l = list(range(0,k))
b = combinations(l, k-1)
for i in l:
indx = b[i]
def f(z):
r = dbeta(z, x[i] + alpha, n[i] - x[i] + beta)
for j in indx:
r = r*pbeta(z, x[j] + alpha, n[j] - x[j] + beta)
return r
a = quad(f, 0, 1)[0]
ans.append(a)
return ans
So when calling
x = [10,20,30,50]
n = [100,102,120,130]
best_binominal_bandit(x, n)
I do not receive similar results as they do in their specification. I have the feeling that there are just more iterations in the f function. After all, the bottom line should add up to 1.
I came up with a solution. I will post it here and then close the question. Seems like I misread something and made an easy mistake (that kept vexing me however).
The combination function is not necessary for what I intended, rather the ith element of the list simply needs to be excluded.
def dbeta(x,shape1,shape2):
from scipy.stats import beta
result=beta.pdf(x=x,a=shape1,b=shape2,loc=0,scale=1)
return result
def pbeta(q,shape1,shape2):
from scipy.stats import beta
result=beta.cdf(x=q,a=shape1,b=shape2,loc=0,scale=1)
return result
from scipy.integrate import quad
def best_binominal_bandit(x, n, alpha=1, beta=1):
ans = []
k = len(x)
l = list(range(0,k))
for i in l:
excluded_index = i
indx = l[:excluded_index] + l[excluded_index+1:]
def f(z):
r = dbeta(z, x[i] + alpha, n[i] - x[i] + beta)
print(z)
for j in indx:
r = r*pbeta(z, x[j] + alpha, n[j] - x[j] + beta)
return r
a = quad(f, 0, 1)[0]
ans.append(a)
return ans
All in all this seems to work for a python translation of: p. 648 in
Scott, S. L. (2010). A modern Bayesian look at the multi-armed bandit. Applied Stochastic Models in Business and Industry, 26(6), 639–658. doi:10.1002/asmb.874

Approximating the sine function with polynomials using gaussian elimination

I'm trying to approximate the sine function over an interval with gaussian elimination using python. Using this code.
from copy import deepcopy
def convert_to_row_eschelon(A_, B_):
A = deepcopy(A_)
B = deepcopy(B_)
dim = len(A)
for cc in range(dim):
# pivot_row = A[cc]
for r in range(cc + 1, dim):
leading_term = A[r][cc]
for c in range(cc, dim):
# print(A[r][c], A[r][cc])
A[r][c] = A[r][c] - A[cc][c] * leading_term / A[cc][cc]
B[r] = B[r] - B[cc] * leading_term / A[cc][cc]
return A, B
def back_sub(matrix_pair):
A = matrix_pair[0]
B = matrix_pair[1]
res = [None] * len(B)
for i in range(len(B) - 1, -1, -1):
def f(j):
return A[i][j] * res[j]
res[i] = (B[i] - sum([f(k) for k in range(i + 1, len(B))])) / A[i][i]
return res
def gaussian_elimination(A, B):
return back_sub(convert_to_row_eschelon(A, B))
A = [
[1, 2, 3],
[4, 5, 7],
[23, 12, 12]
]
B = [4, 6, 7]
fig = 10
# print(convert_to_row_eschelon(A, B))
def make_polynomial(x_points, y_points):
# A[x_point index used][degree]
degree = len(x_points)
A = []
for i in range(degree):
A.append([])
for j in range(degree):
A[i].append(x_points[i] ** j) # This is line 45
coeff = gaussian_elimination(A, y_points)
def f(x):
coeff_f = coeff
res = 0
for i in range(len(coeff_f)):
res += x ** i * coeff_f[i]
return res
return f
def generate_x(start, finish, increment):
x_points = []
curr = start
while curr < finish:
x_points.append(curr)
curr += increment
return x_points
from math import sin, pi
start = 0 # These are the intervals
finish = 2 * pi
increment = 0.01
def test_func(x):
return sin(x)
# Creating the polynomial
x_val_f = generate_x(start, finish, increment)
x_val_test = generate_x(start, finish, 0.01)
f = make_polynomial(x_val_f, [test_func(i) for i in x_val_f])
print(f(3))
y_val_f = [f(i) for i in x_val_f]
y_val_test = [test_func(i) for i in x_val_test]
error = sum([abs(y_val_f[i] - y_val_test[i]) for i in range(len(y_val_f))]) / len(y_val_f)
print('average error : {}'.format(error))
# plotting f
import matplotlib.pyplot as plt
plt.plot(x_val_test, y_val_test, label = "test_func")
plt.scatter(x_val_f, y_val_f, label = "f(x)", s = 10)
plt.xlabel('x-axis')
plt.ylabel('y-axis')
plt.ylim(-1,1)
plt.title('Graph')
plt.legend()
plt.show()
But whenever I try making the increment smaller (to make the approximation function more accurately supposedly) python keeps giving me this error.
File "c:/Users/username/Desktop/Curve fitting.py", line 45, in make_polynomial
A[i].append(x_points[i] ** j)
OverflowError: (34, 'Result too large')
Is this just because I have too many points so x_points[i] ** j becomes too big? or have I made a mistake somewhere? and even if I do make it work by making the increment larger some of the points don't match up with the sin function.
0.1 increment plot. Test_func is the sine function and f is the approximation function.
Does anyone know why this happens?
Here is one more screenshot over an increment of 0.07 within the same interval as the one in the code. 0.07 Increment plot. If there are other things that might help with this please let me know.
In such cases, it helps to use a debugger to find out what's going wrong. Or at the very least, use try-except blocks to catch the exception and print your variables to see where your code explodes.
try:
for i in range(degree):
A.append([])
for j in range(degree):
A[i].append(x_points[i] ** j) # This is line 45
except:
print(f"i = {i}; j = {j}")
### output:
i = 310; j = 628
In this case, your code breaks when i = 310 and j = 628. This is because x_points[i] ** j = 3.10 ** 628, which is too big to store in a double.

How to compute the Mass distribution in Python?

Mass distribution is defined as follows.
f is the probability density function of a continuous variable.
Given a set of data values, which are saved in a list, how to approximate this function? Since the integrals in the numerator and the denominator are identical to the expected value of a distribution, can we use the sample mean based approach as follows?
def get_mass_distribution(values):
x = np.linspace(0, max(values), max(values))
mean = sum(values)/len(values)
mass = []
values.sort()
for i in range(len(values)):
mass.append(sum(values[0:i+1])/(mean*(i+1)))
return x, mass
You should use trapezoidal rule to approximate this integral.
def get_mass_distribution(data):
a = np.array(data)
ag = st.gaussian_kde(a)
denom_integral = trapezoidal(ag, 0, max(data), max(data)*10)
Fm = [0]
x = []
k = 0
while(k < max(data)):
x.append(k)
k = k+1
for i in x[1:]:
enum_integral = trapezoidal(ag, 0, i, i*10)
Fm.append(enum_integral/denom_integral)
return x, Fm
def trapezoidal(ag, a, b, n):
h = float(b - a) / n
s = 0.0
s += a*ag(a)[0]/2.0
for i in range(1, n):
s += (a + i*h)*ag(a + i*h)[0]
s += b*ag(b)[0]/2.0
return s * h

Integrate a function by the trapezoidal rule- Python

Here is the homework assignment I'm trying to solve:
A further improvement of the approximate integration method from the last question is to divide the area under the f(x) curve into n equally-spaced trapezoids.
Based on this idea, the following formula can be derived for approximating the integral:
!(https://www.dropbox.com/s/q84mx8r5ml1q7n1/Screenshot%202017-10-01%2016.09.32.png?dl=0)!
where h is the width of the trapezoids, h=(b−a)/n, and xi=a+ih,i∈0,...,n, are the coordinates of the sides of the trapezoids. The figure above visualizes the idea of the trapezoidal rule.
Implement this formula in a Python function trapezint( f,a,b,n ). You may need to check and see if b > a, otherwise you may need to swap the variables.
For instance, the result of trapezint( math.sin,0,0.5*math.pi,10 ) should be 0.9979 (with some numerical error). The result of trapezint( abs,-1,1,10 ) should be 2.0
This is my code but It doesn't seem to return the right values.
For print ((trapezint( math.sin,0,0.5*math.pi,10)))
I get 0.012286334153465965, when I am suppose to get 0.9979
For print (trapezint(abs, -1, 1, 10))
I get 0.18000000000000002, when I am suppose to get 1.0.
import math
def trapezint(f,a,b,n):
g = 0
if b>a:
h = (b-a)/float(n)
for i in range (0,n):
k = 0.5*h*(f(a+i*h) + f(a + (i+1)*h))
g = g + k
return g
else:
a,b=b,a
h = (b-a)/float(n)
for i in range(0,n):
k = 0.5*h*(f(a + i*h) + f(a + (i + 1)*h))
g = g + k
return g
print ((trapezint( math.sin,0,0.5*math.pi,10)))
print (trapezint(abs, -1, 1, 10))
Essentially, your return g statement was indented, when it should not have been.
Also, I removed your duplicated code, so it would adhere to "DRY" "Don't Repeat Yourself" principle, which prevents errors, and keeps code simplified and more readable.
import math
def trapezint(f, a, b, n):
g = 0
if b > a:
h = (b-a)/float(n)
else:
h = (a-b)/float(n)
for i in range (0, n):
k = 0.5 * h * ( f(a + i*h) + f(a + (i+1)*h) )
g = g + k
return g
print ( trapezint( math.sin, 0, 0.5*math.pi, 10) )
print ( trapezint(abs, -1, 1, 10) )
0.9979429863543573
1.0000000000000002
This variation reduces the complexity of branches and reduces number of operations. The summation in last step is reduced to single operation on an array.
from math import pi, sin
def trapezoid(f, a, b, n):
if b < a:
a,b = b, a
h = (b - a)/float(n)
g = [(0.5 * h * (f(a + (i * h)) + f(a + ((i + 1) * h)))) for i in range(0, n)]
return sum(g)
assert trapezoid(sin, 0, 0.5*pi, 10) == 0.9979429863543573
assert trapezoid(abs, -1, 1, 10) == 1.0000000000000002

Solving a 9x9 matric with gausian emlinination with pivoting in python

Im needing to solve a whole range of 8x8 and 9x9 matrices so thought I could build a python program to make the whole thing easier.
So far I have managed to create:
from __future__ import division
import numpy as np
def solveEqns(A,v):
def lu( A ):
#Factor A into LU by Gaussian elimination with scaled partial pivoting
n, m = np.shape( A )
if n != m:
print "Error: input matrix is not square"
return None
# Generate initial index vector
p = range( n )
# Determine the largest (in magnitude) element in each row. These
# factors are used to scale the pivot elements for comparison purposes
# when deciding which row to use as a pivot row.
s = [0] * n
for i in xrange( n ):
smax = 0.0
for j in xrange( n ):
smax = max( smax, abs( A[i][j] ) )
s[i] = smax
# Begin Gaussian elimination.
for k in xrange( n - 1 ):
# Find the remaining row with the largest scaled pivot.
rmax = 0.0
for i in xrange( k, n ):
r = abs( A[p[i][k]] / s[p[i]] )
if r > rmax:
rmax = r
j = i
# Row j has the largest scaled pivot, so "swap" that row with the
# current row (row k). The swap is not actually done by copying rows,
# but by swaping two entries in an index vector.
p[j], p[k] = ( p[k], p[j] )
# Now carry out the next elimination step as usual, except for the
# added complication of the index vector.
for i in xrange( k + 1, n ):
xmult = A[p[i],k] / A[p[k],k]
A[p[i],k] = xmult
for j in xrange( k + 1, n ):
A[p[i],j] = A[p[i],j] - xmult * A[p[k],j]
# All done, return factored matrix A and permutation vector p
return ( A, p )
def solve( A, p, b ):
#Solves Ax = b given an LU factored matrix A and permuation vector p
n, m = np.shape( A )
if n != m:
print "Error: input matrix is not square"
return None
# Forward solve
x = np.zeros( n )
for k in xrange( n - 1 ):
for i in xrange( k + 1, n ):
b[p[i]] = b[p[i]] - A[p[i],k] * b[p[k]]
# Backward solve
for i in xrange( n - 1, -1, -1 ):
sum = b[p[i]]
for j in xrange( i + 1, n ):
sum = sum - A[p[i],j] * x[j]
x[i] = sum / A[p[i],i]
# All done, return solution vector
return x
lu(A)
return solve(A,p,v)
def circuit():
A = np.array([[1,0,0,0,0,8,0,0,0],[0,1,0,0,5,0,0,0,0],[0,1,0,0,5,0,0,0,0],[0,0,0,1,-1,1,0,0,0],[0,0,1,0,0,0,1,-1,0],[0,0,1,0,0,0,1,0,-1],[0,1,0,0,-1,0,0,0,1],[1,0,0,0,0,-1,0,1,0],[1,-1,0,1,0,0,0,0,0]])
v = np.array([9,-12,-0.5,0,0,0,0,0,0])
I = solveEqns(A,v)
return I
to solve the 9x9 matrix A at the end. This is one of the easier ones i need to solve so can solve it outside of python to check if the results coming through are accurate.
Im getting a traceback error on line 26 of:
Traceback (most recent call last):
File "<ipython-input-110-6daf773db1e3>", line 1, in <module>
solveEqns(A,b)
File "C:/Users/SamMc/Documents/Python Scripts/q6u1510416 v4.py", line 65, in solveEqns
lu(A)
File "C:/Users/SamMc/Documents/Python Scripts/q6u1510416 v4.py", line 26, in lu
r = abs( A[p[i][k]] / s[p[i]] )
TypeError: 'int' object has no attribute '__getitem__'
which i cant figure out why its not pulling through a number from the matrix.
Any help would be greatly appreciated.
Thanks
Sam
you might use gauss elimination via scaled pivoting. the code is shown below.
import numpy as np
def gauss_pivot(a,b,tol=1.0e-12):
"""
x = gaussPivot(a,b,tol=1.0e-12).
Solves [a]{x} = {b} by Gauss elimination with
scaled row pivoting
"""
a = np.copy(a)
b = np.copy(b)
n = len(b)
assert (np.all(np.shape(a) ==(n,n))) # check if a is a square matrix
# Set up scale factors
s = np.zeros(n)
for i in range(n):
s[i] = max(np.abs(a[i,:])) # find the max of each row
for k in range(0, n-1): #pivot row
# Row interchange, if needed
p = np.argmax(np.abs(a[k:n,k])/s[k:n]) # find which row has max item for each col k, and scale by s
if abs(a[p,k]) < tol:
raise Exception("Matrix is singular")
if p != k: # swap rows if current row does not contain max item with the one contains max item within same col
a[[k,p+k],:] = a[[p+k, k],:]
b[k],b[p+k] = b[p+k],b[k]
s[k],s[p+k] = s[p+k],s[k]
# Elimination phase of matrix a
for i in range(k+1,n):
if a[i,k] != 0.0: # skip if a(i,k) is already zero
lam = a [i,k]/a[k,k]
a[i,k:n] = a[i,k:n] - lam*a[k,k:n]
b[i] = b[i] - lam*b[k]
if abs(a[n-1,n-1]) < tol:
raise Exception("Matrix is singular")
# Back substitution phase, solution is substituted by b
x = np.zeros_like(b)
x[n-1] = b[n-1]/a[n-1,n-1]
for k in range(n-2,-1,-1):
x[k] = (b[k] - np.dot(a[k,k+1:n],x[k+1:n]))/a[k,k]
return x
a = np.random.randn(100,100)*10
b = np.random.randn(100)*10
x = gauss_pivot(a,b)
if np.allclose(np.dot(a,x), b) == True:
print("x is the correct solution")
If you want the code to perform faster you might probably replace x by b, so upon function return b contains the solution.
you might also slightly modify elimination phase so elements of matrix a below diagonal are not zeroed, since there are irrelevant during back substitution phase. Therefore, the code becomes as shown below:
import numpy as np
def gauss_pivot(a,b,tol=1.0e-12):
"""
x = gaussPivot(a,b,tol=1.0e-12).
Solves [a]{x} = {b} by Gauss elimination with
scaled row pivoting
"""
a = np.copy(a)
b = np.copy(b)
n = len(b)
assert (np.all(np.shape(a) ==(n,n))) # check if a is a square matrix
# Set up scale factors
s = np.zeros(n)
for i in range(n):
s[i] = max(np.abs(a[i,:])) # find the max of each row
for k in range(0, n-1): #pivot row
# Row interchange, if needed
p = np.argmax(np.abs(a[k:n,k])/s[k:n]) # find which row has max item for each col k, and scale by s
if abs(a[p,k]) < tol:
raise Exception("Matrix is singular")
if p != k: # swap rows if current row does not contain max item with the one contains max item within same col
a[[k,p+k],:] = a[[p+k, k],:]
b[k],b[p+k] = b[p+k],b[k]
s[k],s[p+k] = s[p+k],s[k]
# Elimination phase of matrix a
for i in range(k+1,n):
if a[i,k] != 0.0: # skip if a(i,k) is already zero
lam = a [i,k]/a[k,k]
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
b[i] = b[i] - lam*b[k]
if abs(a[n-1,n-1]) < tol:
raise Exception("Matrix is singular")
# Back substitution phase, solution is substituted by b
b[n-1] = b[n-1]/a[n-1,n-1]
for k in range(n-2,-1,-1):
b[k] = (b[k] - np.dot(a[k,k+1:n],b[k+1:n]))/a[k,k]
return b
To use LU decomposition instead which is more ideal for b containing more than one column, the LU code is shown below
import numpy as np
def lu_decomp(a,tol=1.0e-9):
a = np.copy(a)
n = len(a)
assert (np.all(np.shape(a) ==(n,n))) # check if a is a square matrix
seq = np.arange(n, dtype=int)
s = np.zeros((n))
for i in range(n):
s[i] = max(abs(a[i,:]))
for k in range(0,n-1):
p = np.argmax(np.abs(a[k:n,k])/s[k:n])
if abs(a[p,k]) < tol:
raise Exception("Matrix is singular")
if p != k:
a[[k,p+k],:] = a[[p+k, k],:]
s[k],s[p+k] = s[p+k],s[k]
seq[k], seq[p+k] = seq[p+k],seq[k]
# Elimination
for i in range(k+1,n):
if a[i,k] != 0.0:
lam = a[i,k]/a[k,k]
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
a[i,k] = lam
return a,seq
def lu_solve(a,b,seq):
n = len(a)
x = b.copy()
for i in range(n):
x[i] = b[seq[i]]
# Solution
for k in range(1,n):
x[k] = x[k] - np.dot(a[k,0:k],x[0:k])
x[n-1] = x[n-1]/a[n-1,n-1]
for k in range(n-2,-1,-1):
x[k] = (x[k] - np.dot(a[k,k+1:n],x[k+1:n]))/a[k,k]
return x
a2 = np.random.randn(500,500)*100
b2 = np.random.randn(500,20)*100
a_decomposed, seq = lu_decomp(a2)
x2 = np.zeros_like(b2)
for col in range(b2.shape[1]):
x2[:,col] = lu_solve(a_decomposed, b2[:, col], seq)
if np.allclose(np.dot(a2,x2), b2) == True:
print("x2 is the correct solution")
Both methods gives the the output,
Gauss Elimination
x is the correct solution
LU method
x2 is the correct solution
I recommend you use scipy linalg package, from scipy.linalg import solve, lu_factor, lu_solve.
They perform way faster for large matrix size. you can use the same code above but annotate them with numba jit so for large matrix the performance is way better.
from numba import jit
#jit
def gauss_pivot(a, b):
...
...
acknowledgement: codes inspired from the book numerical methods in science and engineering with Python by Prof. Jaan Kiusalaas
https://www.amazon.co.uk/Numerical-Methods-Engineering-Python-3/dp/1107033853/ref=sr_1_1?ie=UTF8&qid=1517845946&sr=8-1&keywords=numerical+method+in+science+and+engineering+with+python

Categories

Resources