Interpolation of sin(x) using Python - python

I am working on a homework problem for which I am supposed to make a function that interpolates sin(x) for n+1 interpolation points and compares the interpolation to the actual values of sin at those points. The problem statement asks for a function Lagrangian(x,points) that accomplishes this, although my current attempt at executing it does not use 'x' and 'points' in the loops, so I think I will have to try again (especially since my code doesn't work as is!) However, why I can't I access the items in the x_n array with an index, like x_n[k]? Additionally, is there a way to only access the 'x' values in the points array and loop over those for L_x? Finally, I think my 'error' definition is wrong, since it should also be an array of values. Is it necessary to make another for loop to compare each value in the 'error' array to 'max_error'? This is my code right now (we are executing in a GUI our professor made, so I think some of the commands are unique to that such as messages.write()):
def problem_6_run(problem_6_n, problem_6_m, plot, messages, **kwargs):
n = problem_6_n.value
m = problem_6_m.value
messages.write('\n=== PROBLEM 6 ==========================\n')
x_n = np.linspace(0,2*math.pi,n+1)
y_n = np.sin(x_n)
points = np.column_stack((x_n,y_n))
i = 0
k = 1
L_x = 1.0
def Lagrange(x, points):
for i in n+1:
for k in n+1:
return L_x = (x- x_n[k] / x_n[i] - x_n[k])
return Lagrange = y_n[i] * L_x
error = np.sin(x) - Lagrange
max_error = 0
if error > max_error:
max_error = error
print.messages('Maximum error = &g' % max_error)
plot.draw_lines(n+1,np.sin(x))
plot.draw_points(m,Lagrange)
plots.draw_points(m,error)
Edited:
Yes, the different things ThiefMaster mentioned are part of my (non CS) professor's environment; and yes, voithos, I'm using numpy and at this point have definitely had more practice with Matlab than Python (I guess that's obvious!). n and m are values entered by the user in the GUI; n+1 is the number of interpolation points and m is the number of points you plot against later.
Pseudocode:
Given n and m
Generate x_n a list of n evenly spaced points from 0 to 2*pi
Generate y_n a corresponding list of points for sin(x_n)
Define points, a 2D array consisting of these ordered pairs
Define Lagrange, a function of x and points
for each value in the range n+1 (this is where I would like to use points but don't know how to access those values appropriately)
evaluate y_n * (x - x_n[later index] / x_n[earlier index] - x_n[later index])
Calculate max error
Calculate error interpolation Lagrange - sin(x)
plot sin(x); plot Lagrange; plot error
Does that make sense?

Some suggestions:
You can access items in x_n via x_n[k] (to answer your question).
Your loops for i in n+1: and for k in n+1: only execute once each, one with i=n+1 and one with k=n+1. You need to use for i in range(n+1) (or xrange) to get the whole list of values [0,1,2,...,n].
in error = np.sin(x) - Lagrange: You haven't defined x anywhere, so this will probably result in an error. Did you mean for this to be within the Lagrange function? Also, you're subtracting a function (Lagrange) from a number np.sin(x), which isn't going to end well.
When you use the return statement in your def Lagrange you are exiting your function. So your loop will never loop more than once because you're returning out of the function. I think you might actually want to store those values instead of returning them.
Can you write some pseudocode to show what you'd like to do? e.g.:
Given a set of points `xs` and "interpolated" points `ys`:
For each point (x,y) in (xs,ys):
Calculate `sin(x)`
Calculate `sin(x)-y` being the difference between the function and y
.... etc etc
This will make the actual code easier for you to write, and easier for us to help you with (especially if you intellectually understand what you're trying to do, and the only problem is with converting that into python).
So : try fix up some of these points in your code, and try write some pseudocode to say what you want to do, and we'll keep helping you :)

Related

python polynomial fit with some coefficients being fixed, order should be a parameter, need to create list of variables?

I need some help writing a pretty simple code (at least in pseudo code):
I want fit data using a polynomial of order n, where n is a parameter and should be changable. On top of that I would like to always keep the first three coefficients fixed to be zero. So I need something like
order = 5
def poly(x,c0=0,c1=0,c2=0,c3,c4,c5):
return numpy.polynomial.polynomial.polyval(x, [c0,c1,c2,c3,c4,c5], tensor=False)
popt, pcov = scipy.optimize.curve_fit(poly,x,y)
So problems I can not sove atm is:
How do I create a polynomial function with n number of coefficents? I basicly need to create a list of variables of length n.
If that is solved than we could put c0 to c2 to 0.
I hope I was able to make myself clear, if not please help me to refine my question.
You currently do not keep the first 3 coefficient fixed to 0, you just give them a default value.
Arbitrary argument lists seem to be what you are looking for:
def poly(x,*args):
return numpy.polynomial.polynomial.polyval(x, [0,0,0] + list(args), tensor=False)
If the number of arguments MUST be of fixed length (for instance n), you can check len(args) and raise an error if necessary.
Calling poly(x,a,b,c) now returns the polynomial function with the coefficients [0,0,0,a,b,c]
You can find more information in Python's documentation: https://docs.python.org/3/tutorial/controlflow.html#more-on-defining-functions

Python plot of force in Lennard-Jones system gives TypeError

I am trying to plot the force on the ith particle as function of its distance from the jth particle (ie. xi-xj) in a Lennard-Jones system. The force is given by
where sigma and epsilon are two parameters, Xi is a known quantity and Xj is variable. The force directs from the ith particle to the jth particle.
The code that I have written for this is given below.
from pylab import*
from numpy import*
#~~~ ARGON VALUES ~~~~~~~~(in natural units)~~~~~~~~~~~~~~~~
epsilon=0.0122 # depth of potential well
sigma=0.335 # dist of closest approach
xi=0.00
xj=linspace(0.1,1.0,300)
f = 48.0*epsilon*( ((sigma**12.0)/((xi-xj)**13.0)) - ((sigma**6.0)/2.0/((xi-xj)**7.0)) ) * float(xj-xi)/abs(xi-xj)
plot(xj,f,label='force')
legend()
show()
But it gives me this following error.
f = 48.0*epsilon*( ((sigma**12.0)/((xi-xj)**11.0)) - ((sigma**6.0)/2.0/((xi-xj)**5.0)) ) * float(xj-xi)/abs(xi-xj)
TypeError: only length-1 arrays can be converted to Python scalars
Can someone help me solve this problem. Thanks in advance.
The error is with this part of the expression:
float(xj-xi)
Look at the answer to a related question. It appears to be conflict between Python built-in functions and Numpy functions.
If you take out the 'float' it at least returns. Does it give the correct numbers?
f = 48.0*epsilon*( ((sigma**12.0)/((xi-xj)**11.0)) - ((sigma**6.0)/2.0/((xi-xj)**5.0)) ) * (xj-xi)/abs(xi-xj)
Instead of the term float(xj-xi)/abs(xi-xj) you should use
sign(xj-xi)
If you really want to do the division, since xi and xj are already floats you could just do:
(xj-xi)/abs(xi-xj)
More generally, if you need to convert a numpy array of ints to floats you could use either of:
1.0*(xj-xi)
(xj-xi).astype(float)
Even more generally, it's helpful in debugging to not use equations that stretch across the page because with smaller terms you can identify the location of the errors more easily. It also often runs faster. For example, here you calculate xi-xj four times, when really it only needs to be done once. And it would be easier to read:
x = xi -xj
f = 48*epsilon*(s**12/x**13 - s**6/2/x**7)
f *= sign(-x)
The TypeError is due to float(xi-xj). float() cannot convert an iterable to a single scalar value. Instead, iterate over xj and convert each value in xi-xj to float. This can be easily done with
x = [float(j - xi) for j in xj)]

ChiSquare calculation returning all zeros

EDIT: after more trial and error, I figured out that for some reason, python says that 1/52 is 0, can anyone explain me why, so I can avoid this problem in the future?
I've been struggling with a script for a while now, mainly because me or my fellow students simply can't find out what's wrong with it.
Trying to keep things simple, we've got data and a model and we have to rescale some of the datapoints to the model and then do a chi2square minimalization in order to find the best rescaling factor.
I've tried multiple things already. Tried putting everything in 1 loop, when that didn't work, I tried splitting the loops up etc.
The relevant part of my code looks like this:
#Here I pick the values of the model that correspond to the data
y4 = np.zeros((len(l),1))
for x in range(0,len(l)):
if l[x] < 2.16:
for y in range(0,len(lmodel)):
if lmodel[y] == l[x]:
y4[x] = y2[y]
elif lmodel[y] < l[x] < lmodel[y+1]:
y4[x] = (y2[y] + y2[y+1])/2
else:
y4[x] = y1[x]
#Do Chi2 calculation
#First, I make a matrix with all the possible rescaled values
chi2 = np.zeros((200,1))
y3 = np.zeros((len(l),len(chi2)))
for z in range(0,len(chi2)):
for x in range(0,len(l)):
if l[x] < 2.16:
y3[x,z] = y1[x]*10**(0.4*Al[x]*z/100)
else:
y3[x,z] = y1[x]
#Here I calculate the chisquare for each individual column and put it in the chi2 array
dummy = np.zeros((len(l),1))
for x in range(0,len(chi2)):
for t in range(0, len(l)):
dummy[t] = (1/52)*((y3[t,x] - y4[t])/fle[t])**2
chi2[x] = np.sum(dummy)
The thing is that no matter what I try, for some reason, my dummy array is always all zeros, making every single chi square value 0.
I've tried making 'dummy' a matrix and summing afterwards, I've tried printing individual values for the calculation of the dummy[t]'s, and some of them were 0 (as expected), some weren't, so logically, if the individual values aren't all 0, neither should every value in dummy be.
I just can't find where I go wrong, and why I keep getting arrays of zeros.
In Python 2 (which most people are still using), 1 / 52 is an integer division, so returns 0. You can fix it by explicitly using floating point numbers, e.g. 1.0 / 52.
In Python 3, this is no longer true--dividing two integers can return a float.

Using other data with a function of the form f(x,y) = f(x,y,z).sum(axis=-1)

So, in my previous question wflynny gave me a really neat solution (Surface where height is a function of two functions, and a sum over the third). I've got that part working for my simple version, but now I'm trying to improve on this.
Consider the following lambda function:
x = np.arange(0,100, 0.1)
y = np.sin(y);
f = lambda xx: (xx-y[x=xx])**2
values = f(x)
Now, in this scenario it works. In fact, the [x=xx] is trivial in the example. However, the example can be extended:
x = np.arange(0,100, 0.1)
z = np.sin(y);
f = lambda xx, yy: ( (xx-z[x=xx])**2 + yy**2)**0.5
y = np.arange(0,100,0.1)
[xgrid, ygrid] = np.meshgrid(x,y);
values = f(xgrid,ygrid)
In this case, the error ValueError: boolean index array should have 1 dimension is generated. This is because z.shape is different from xgrid.shape, I think.
Note that here, y=np.sin(y) is a simplification. It's not a function but an array of arbitrary values. We really need to go to that array to retrieve them.
I do not know what the proper way to implement this is. I am going to try some things, but I hope that somebody here will give me hints or provide me with the proper way to do this in Python.
EDIT: I originally thought I had solved it by using the following:
retrieve = lambda pp: map(lambda pp: dataArray[pp==phiArray][0], phi)
However, this merely returns the dataArray. Suppose dataArray contains a number of 'maximum' values for the polar radius. Then, you would normally incorporate this by saying something like g = lambda xx, yy: f(xx,yy) * Heaviside( dataArray - radius(xx,yy)). Then g would properly be zero if the radius is too large.
However, this doesn't work. I'm not fully sure but the behaviour seems to be something like taking a single value of dataArray instead of the entire array.
Thanks!
EDIT: Sadly, this stuff has to work and I can't spend more time on making it nice. Therefore, I've opted for the dirty implementation. The actual thing I was interested in would be of the sort as the g = lambda xx, yy written above, so I can implement that directly (dirty) instead of nicely (without nested for loops).
def envelope(xx, yy):
value = xx * 0.
for i in range(0,N): #N is defined somewhere, and xx.shape = (N,N)
for j in range(0,N):
if ( dataArray[x=xx[i,j]][0] > radius(xx[i,j],yy[i,j])):
value[i,j] = 1.
else:
value[i,j] = 0.
return value
A last resort, but it works. And, sometimes results matter over writing good code, especially when there's a deadline coming up (and you are the only one that cares about good code).
I would still be very much interested in learning how to do this properly, if there is a proper way, and thus increase my fluency in clean Python.

A 'simple' boundary value/ initial value p‌r‌o‌b‌l‌e‌m in numpy

tl/dr: I have a numpy boundary/initial value problem and want to see if I'm approaching this the right way. I'm fairly new with numpy. I'm presenting a simplified version of the problem.
I have 2 functions a and b defined for integer values of t and x, which I'm trying to calculate for positive x and t (say up to N ). I want to figure out the best way to do this with numpy.
I have boundary values at t=0 and x=0, a(t,x) depends only on a(t-1,x-1) and b(t-1,x-1) while b(t,x) depends on lots of values of a with smaller t, x . This is what makes it 'simple'. We have
a=1 for t=0 and for x=0.
b=0.1 for for t=0 and b=1 for x=0. At x=t=0, we get b=0.1.
In the interior, a(t,x) = a(t-1,x-1) - b(t-1,x-1).
Now the hard part. b(t,x) = a(t-1,x-1) S(t, t-1) + a(t-2,x-2) S(t,t-2) + ...
where S(t,y) is a sum equal to f(a(t-1,1)) + f(a(t-1,2)) + ... + f(a(t-1,y)) for some function f (If you need something specific, you could assume it's just a + a**2).
So my plan is to do this basically as:
initialize values
loop over t:
update a
loop over y:
define the S(t,y) #each step is vectorizable I think
loop over x:
set b to equal the dot product between vector of S and slice of a.
My question: Is this a reasonable approach - can I cut out any of those loops, or should I take a different tack entirely?
Bonus question: Any likely errors for a numpy newb to make coding this?

Categories