My Python trapezoidal code is saying x not defined - python-3.x

I am trying to find the integration of Sin^2(x)/x^2 using trapezoidal rule but while running it is saying x id not defined. Can anyone suggest me what is wrong?
import math
c=math.sin`
def trapezoidal(f, a, b, N):
if x!=0:
h=(b-a)/N
s=0.0
s+=f(a)/2.0
for i in range (1,N):
s+=f(a+i*h)
s+=f(b)/2.0
Y=s*h
else:
y=1
return Y`
for n in range (1,11):
N=2**n
result=trapezoidal(lambda x:((c(x)*c(x))/(x**2)), 0, 1000, N)
print(repr(n).rjust(10), repr(result).rjust(30))`

You're not calling the x in the function. In your case you want to loop over every element in the function f.
If you don't want to use the pythonic way, you can have a look at numpy and scipy. These packages offer optimised functions for basic operation such as integrations and matrix calculations. Have a look at np.trapz (https://docs.scipy.org/doc/numpy/reference/generated/numpy.trapz.html), sp.integrate (https://docs.scipy.org/doc/scipy-0.18.1/reference/tutorial/integrate.html)

Related

Implementing alternative Fibonacci sequence

So I'm struggling with Question 3. I think the representation of L would be a function that goes something like this:
import numpy as np
def L(a, b):
#L is 2x2 Matrix, that is
return(np.dot([[0,1],[1,1]],[a,b]))
def fibPow(n):
if(n==1):
return(L(0,1))
if(n%2==0):
return np.dot(fibPow(n/2), fibPow(n/2))
else:
return np.dot(L(0,1),np.dot(fibPow(n//2), fibPow(n//2)))
Given b I'm pretty sure I'm wrong. What should I be doing? Any help would be appreciated. I don't think I'm supposed to use the golden ratio property of the Fibonacci series. What should my a and b be?
EDIT: I've updated my code. For some reason it doesn't work. L will give me the right answer, but my exponentiation seems to be wrong. Can someone tell me what I'm doing wrong
With an edited code, you are almost there. Just don't cram everything into one function. That leads to subtle mistakes, which I think you may enjoy to find.
Now, L is not function. As I said before, it is a matrix. And the core of the problem is to compute its nth power. Consider
L = [[0,1], [1,1]]
def nth_power(matrix, n):
if n == 1:
return matrix
if (n % 2) == 0:
temp = nth_power(matrix, n/2)
return np.dot(temp, temp)
else:
temp = nth_power(matrix, n // 2)
return np.dot(matrix, np.dot(temp, temp))
def fibPow(n):
Ln = nth_power(L, n)
return np.dot(L, [0,1])[1]
The nth_power is almost identical to your approach, with some trivial optimization. You may optimize it further by eliminating recursion.
First thing first, there is no L(n, a, b). There is just L(a, b), a well defined linear operator which transforms a vector a, b into a vector b, a+b.
Now a huge hint: a linear operator is a matrix (in this case, 2x2, and very simple). Can you spell it out?
Now, applying this matrix n times in a row to an initial vector (in this case, 0, 1), by matrix magic is equivalent to applying nth power of L once to the initial vector. This is what Question 2 is about.
Once you determine how this matrix looks like, fibPow reduces to computing its nth power, and multiplying the result by 0, 1. To get O(log n) complexity, check out exponentiation by squaring.

Numerical evaluation of the exponential integral function using trapezoidal rule

I want to evaluate the exponential integral function numerically using trapezoidal rule.This function is defined as:
The reference is available here.
This function is already available in some libraries for example scipy.special. For some reasons I do not want to use these libraries. Instead, I need to evaluate this function directly by the trapezoidal rule. I wrote the trapezoidal rule and checked it to make sure it works fine.
Then I used it for numerical evaluation of the Ei function. Unfortunately the results is not correct for example I want to evaluate Ei(1) which is equal to 1.89511 but the code I have written returns infinity which is wrong. Here is the code:
import numpy as np
# Integration using Trapezoidal rule
def trapezoidal(f, a, b, n):
h = float(b - a) / n
s = 0.0
s += f(a)/2.0
for i in range(1, n):
s += f(a + i*h)
s += f(b)/2.0
return s * h
# Define integrand
def Ei(t):
return - np.exp(-t) / t
# Define Ei(1)
A = trapezoidal(Ei, -1, np.inf, 20)
print (A)
# Checking Ei(1)
from scipy.special import expi
print (expi(1))
Do you know how I can modify the above code so I can get correct results?
Thanks!
1) You cannot define range ending woth +inf and divide it onto 20 parts.
Instead you can choose arbitrary right limit and increase it until difference abs(integral(limit(i+1))-integral(limit(i))) becomes negligible
2) Consider function evaluation in zero point (if occurs). It causes division by zero
If argument is too close to zero, try to shift it a bit.

Multiplying functions together in Python

I am using Python at the moment and I have a function that I need to multiply against itself for different constants.
e.g. If I have f(x,y)= x^2y+a, where 'a' is some constant (possibly list of constants).
If 'a' is a list (of unknown size as it depends on the input), then if we say a = [1,3,7] the operation I want to do is
(x^2y+1)*(x^2y+3)*(x^2y+7)
but generalised to n elements in 'a'. Is there an easy way to do this in Python as I can't think of a decent way around this problem? If the size in 'a' was fixed then it would seem much easier as I could just define the functions separately and then multiply them together in a new function, but since the size isn't fixed this approach isn't suitable. Does anyone have a way around this?
You can numpy ftw, it's fairly easy to get into.
import numpy as np
a = np.array([1,3,7])
x = 10
y = 0.2
print(x ** (2*y) + a)
print(np.sum(x**(2*y)+a))
Output:
[3.51188643 5.51188643 9.51188643]
18.53565929452874
I haven't really got much for it to be honest, I'm still trying to figure out how to get the functions to not overlap.
a=[1,3,7]
for i in range(0,len(a)-1):
def f(x,y):
return (x**2)*y+a[i]
def g(x,y):
return (x**2)*y+a[i+1]
def h(x,y):
return f(x,y)*g(x,y)
f1= lambda y, x: h(x,y)
integrate.dblquad(f1, 0, 2, lambda x: 1, lambda x: 10)
I should have clarified that the end result can't be in floats as it needs to be integrated afterwards using dblquad.

How do I call a list of numpy functions without a for loop?

I'm doing data analysis that involves minimizing the least-square-error between a set of points and a corresponding set of orthogonal functions. In other words, I'm taking a set of y-values and a set of functions, and trying to zero in on the x-value that gets all of the functions closest to their corresponding y-value. Everything is being done in a 'data_set' class. The functions that I'm comparing to are all stored in one list, and I'm using a class method to calculate the total lsq-error for all of them:
self.fits = [np.poly1d(np.polyfit(self.x_data, self.y_data[n],10)) for n in range(self.num_points)]
def error(self, x, y_set):
arr = [(y_set[n] - self.fits[n](x))**2 for n in range(self.num_points)]
return np.sum(arr)
This was fine when I had significantly more time than data, but now I'm taking thousands of x-values, each with a thousand y-values, and that for loop is unacceptably slow. I've been trying to use np.vectorize:
#global scope
def func(f,x):
return f(x)
vfunc = np.vectorize(func, excluded=['x'])
…
…
#within data_set class
def error(self, x, y_set):
arr = (y_set - vfunc(self.fits, x))**2
return np.sum(arr)
func(self.fits[n], x) works fine as long as n is valid, and as far as I can tell from the docs, vfunc(self.fits, x) should be equivalent to
[self.fits[n](x) for n in range(self.num_points)]
but instead it throws:
ValueError: cannot copy sequence with size 10 to array axis with dimension 11
10 is the degree of the polynomial fit, and 11 is (by definition) the number of terms in it, but I have no idea why they're showing up here. If I change the fit order, the error message reflects the change. It seems like np.vectorize is taking each element of self.fits as a list rather than a np.poly1d function.
Anyway, if someone could either help me understand np.vectorize better, or suggest another way to eliminate that loop, that would be swell.
As the functions in question all have a very similar structure we can "manually" vectorize once we've extracted the poly coefficients. In fact, the function is then a quite simple one-liner, eval_many below:
import numpy as np
def poly_vec(list_of_polys):
O = max(p.order for p in list_of_polys)+1
C = np.zeros((len(list_of_polys), O))
for p, c in zip(list_of_polys, C):
c[len(c)-p.order-1:] = p.coeffs
return C
def eval_many(x,C):
return C#np.vander(x,11).T
# make example
list_of_polys = [np.poly1d(v) for v in np.random.random((1000,11))]
x = np.random.random((2000,))
# put all coeffs in one master matrix
C = poly_vec(list_of_polys)
# test
assert np.allclose(eval_many(x,C), [p(x) for p in list_of_polys])
from timeit import timeit
print('vectorized', timeit(lambda: eval_many(x,C), number=100)*10)
print('loopy ', timeit(lambda: [p(x) for p in list_of_polys], number=10)*100)
Sample run:
vectorized 6.817315469961613
loopy 56.35076989419758

Scipy equation system with multiple equations

Hello I have a problem using Scipy's fsolve function when I have an equation system.
My code only let's me have as much variables as there are equations in my system, but we all know that in practice, you can have more equations than variables, especially when the solution is not a concrete number but a range of numbers, an additional equation can help narrow down the "haystack" so to speak.
How to insert more equations than variables is my question?
Suppose I have the following non-linear system:
A/B=0.4583(3)
A/C=0.25
A/D=0.72(2)
B/C=0.54(54)
So I have the following code for this:
from scipy.optimize import *
from numpy import *
def FUNC(arg):
A,B,C,D=arg
UNK=empty((4))
UNK[0]= A/B-0.458333333333333
UNK[1]= A/C-0.25
UNK[2]= A/D-0.722222222222222
UNK[3]= B/C-0.545454545454546
return UNK
SOLVED= fsolve(FUNC, [1.0]*4)
print (SOLVED)
The problem is that I also know the following information:
B/D=1.57(57)
C/D=2.8(8)
How can I insert these 2 additional equations into my equation system?
Also how can I display the range of solutions instead of just 1 solution, it seems like fsolve only displays the 1st solution it encounters, not the entire range of possible solutions.
Note that scipy's fsolve is just a Wrapper for the MINPACK's hybrd routine:
The purpose of HYBRD is to find a zero of a system of N non-linear functions in N variables by a modification of the Powell hybrid method. The user must provide a subroutine which calculates the functions. The Jacobian is then calculated by a forward-difference approximation.
If you want to solve a system of 6 equations, your function FUNC needs to be a function of 6 variables. We could do it like this:
import numpy as np
from scipy.optimize import fsolve
def FUNC(arg):
A, B, C, D, E, F = arg
UNK=np.empty((6))
UNK[0]= A/B-0.458333333333333
UNK[1]= A/C-0.25
UNK[2]= A/D-0.722222222222222
UNK[3]= B/C-0.545454545454546
UNK[4]= B/D-1.575757575757575
UNK[5]= C/D-2.888888888888888
return UNK
fsolve(FUNC, x0=[1.0]*6)
It isn't possible to get all solutions with fsolve. But you could try different initial points x0 with the hope to get different solutions.

Resources