multidimensional Euler's method python - python

So I have coded a function for Euler's method. However, I want it to be able to use initial conditions with arbitrary dimensions. So for example, currently my functions works using this:
>>>Euler(f, x0, t0, h, N)
where x0 is a float. However I want it to be able to use this:
>>>Euler(f, [x0], t0, h, N)
where x0 is now a list of floats. (making it multidimensional)
f = function, x0 = initial conditions at time t0,
t0 = initial time, h = step size, N = number of steps.
I have tried using a for loop:
def Euler(f,x0,t0,h,N):
t = t0
y = x0
z = []
v = []
for i in y:
while t <= N:
xval = t
yval = [y]
t += h
y += h * f(t,y[i]) #i have also tried y+= h*f(t, i)
z.append(xval)
v.append(yval)
return z, v
The error I get is TypeError: list indices must be integers or slices, not float. Which I understand, meaning I have to index the y, like using y[0], y[1], etc...but when I do
y+= h* f(t, y[:])
It gives me an error regarding my other function in the file : f = >
TypeError: a float is required
line 22, in <module> vv = -x**3 - x + sin(t)
When I also try
y += h * f(t, y[0])
and I enter
>>>Euler(f, [0., 1.], 0., 1, 10)
line 15, in <module>
y += h * f(t,y[0])
builtins.TypeError: 'float' object is not iterable
I essentially want to return 2 lists, first list is the z, where it returns a list of the time values, and the second list v, where it returns a list of list of each of the results during each step. So far it has worked where I used a float but not a list. So what code am I missing?

Try this:
def Euler(f,x0,t0,h,N):
t = t0
z = []
v = []
for y in x0:
while t <= N:
xval = t
yval = [y]
t += h
y += h * f(t,y) #i have also tried y+= h*f(t, i)
z.append(xval)
v.append(yval)
return z, v
I don't know if this is the intended method seeing as y += h * f(t,y) is dead code and is not used anywhere else
I believe the error is due to not paying attention to the types of your variables. y was a list when you did y = x0.
Fast-forward to this line y += h * f(t,y[i]). In here you try to use the += operator on y and what this does is to append the contents of another iterable to y.
In the same statement, you try to index into y using i. To index into a list, you need to use an integer, but since i is an element of y (which is an array of floats), i cannot be used to index into the list, and this is why you can the error:
TypeError: list indices must be integers or slices, not float.
Also when you do this y+= h* f(t, y[:]), you get the error:
TypeError: a float is required
Because y[:] creates a new list with all the elements of y, thus you are still passing a list to your function.
Finally when you do this y += h * f(t, y[0]), you get the error:
builtins.TypeError: 'float' object is not iterable
Because as I mentioned before, y is a list and += on a list appends the contents of another iterable to the current list. The way it does this is to "iterate" over the second list and append the items in that second list to the first. Since the value h * f(t, y[0]) is not a list, and is not an iterable either, you get the error

Related

How to pass a function as an argument

I would like to find an approximate value for the number pi = 3.14.. by using the Newton method. In order to use it also for some other purpose and thus other function than sin(x), the aim is to implement a generic function that will be passed over as an argument. I have an issue in passing a function as an argument into an other function. I also tried lambda in different variations. The code I am showing below produces the error message: IndexError: list index out of range. I will appreciate your help in solving this issue and eventually make any suggestion in the code which may not be correct. Thanks.
from sympy import *
import numpy as np
import math
x = Symbol('x')
# find the derivative of f
def deriv(f,x):
h = 1e-5
return (lambda x: (f(x+h)-f(x))/h)
def newton(x0,f,err):
A = [x0]
n = 1
while abs(A[n]-A[n-1])<=err:
if n == 1:
y = lambda x0: (math.f(x0))
b = x0-y(x0)/(deriv(y,x0))
A.append(b)
n += 1
else:
k = len(A)
xk = A[k]
y = lambda xk: (math.f(xk))
b = newton(A[k],y,err)-y(newton(A[k],y,err))/deriv(y,k)
A.append(b)
n += 1
return A, A[-1]
print(newton(3,math.sin(3),0.000001))
I don't know why you use sympy because I made it without Symbol
At the beginning you have to calculate second value and append it to list A and later you can calculate abs(A[n]-A[n-1]) (or the same without n: abs(A[-1] - A[-2])) because it needs two values from this list.
Other problem is that it has to check > instead of <=.
If you want to send function sin(x) then you have to use math.sin without () and arguments.
If you want to send function sin(3*x) then you would have to use lambda x: math.sin(3*x)
import math
def deriv(f, x, h=1e-5):
return (f(x+h) - f(x)) / h
def newton(x0, f, err):
A = [x0]
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
while abs(A[-1] - A[-2]) > err: # it has to be `>` instead of `<=`
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
return A, A[-1]
# sin(x)
print(newton(3, math.sin, 0.000001)) # it needs function's name without `()`
# sin(3*x)
print(newton(3, lambda x:math.sin(3*x), 0.000001))
# sin(3*x) # the same without `lambda`
def function(x):
return math.sin(3*x)
print(newton(3, function, 0.000001))
Result:
([3, 3.1425464414785056, 3.1415926532960112, 3.141592653589793], 3.141592653589793)
([3, 3.150770863559604, 3.1415903295877707, 3.1415926535897936, 3.141592653589793], 3.141592653589793)
EDIT:
You may write loop in newton in different way and it will need <=
def newton(x0, f, err):
A = [x0]
while True:
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
if abs(A[-1] - A[-2]) <= err:
break
return A, A[-1]

cannot unpack non-iterable float object

Whenever I run my code I keep getting the error of "cannot unpack non-iterable float object", I'm confused on where the error is coming from, do I have to use the iterating variable in some way?
def DEADBEEF(n):
count = 0
for i in range(n):
x ,y = np.random.uniform(0,1)
if (np.sqrt(x**2 + y**2)<=1):
count = count + 1
answer = count/100
return answer
holder = DEADBEEF(100)
np.random.uniform returns a single float as long as you don't pass the size parameter.
If you want to use x, y = ..., you must supply at least two values on the right side of the assignment.
If you want to assign a float to both x and y using np.random.uniform, try using the size parameter:
x, y = np.random.uniform(0, 1, size=2)

Project Euler Problem 2 in Python with Error Message

I am a complete beginner in coding and was trying problems from Project Euler in Python. Could anyone please explain what is wrong with my code?
Problem: Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
a = []
x = 1
y = 2
for y in range (1, 400000):
if x % 2:
a.append(x)
x = y, y = x + y
print(sum(a))
I received the error message "cannot unpack non-iterable int object". What does this message mean and how to avoid it?
You get that error because you have the line x = y, y = x + y which is interpreted as an attempt to unpack values from an iterable into y, y, so you need to have a new line between x = y and y = x + y.
However since x is assigned with the value of y before y is updated, the better option is to change the line to x, y = y, x + yas JackTheCrab suggested in a comment.
Look the below example as well to explain the error:
price, amount = ["10$", 15] #iterable that can be unpacked
price, amount = 15 # this is just an int and this row will throw error "Cannot unpack non-iterable int object"
x = y, y = x + y
When i take away the addition from the end and the assignment from the beginning, the error still is there.
y, y = x
Output : an error. about non-iterable int ! Because you can unpack an iterable.
iterable = [0, 1, 2]
zero = iterable[0]
one = iterable[1]
two = iterable[2]
is not very good (sorry for my bad english ...) to use, because you have to type iterable[n] again and again. That's why you can unpack such iterables like this:
iterable = [0, 1, 2]
zero, one, two = iterable
This will produce the same result as the above long version.
Back to your code,
x = y, y = x + y
the python interpreter will first work on the assignment (x = ...). To resolve it, it tries to unpack x + y into two values, but this is not possible of course.
To declare two variables on one line, you have to separate the assignments with a colon ;, not a comma. But when you do just that, x will have the same value as y at the beginning, and so y will then be the double of itself, which surely is not what you wanted. Maybe you should do it like this ?
a = []
x = 1
y = 2
for y in range (1, 400000):
if x % 2:
a.append(x)
x, y = y, x + y
# above is equivalent to
# temp = y
# y = x + y
# x = temp
print(sum(a))

SymPy: Expression for Summation of Symbols in a List

I'm writing a program that evaluates the power series sum_{m=0}{oo} a[m]x^m, where a[m] is recursively defined: a[m]=f(a[m-1]). I am generating symbols as follows:
a = list(sympy.symbols(' '.join([('a%d' % i) for i in range(10)])))
for i in range(1, LIMIT):
a[i] = f_recur(a[i-1], i-1)
This lets me refer to the symbols a0,a1,...,a9 using a[0],a[1],...,a[9], and a[m] is a function of a[m-1] given by f_recur.
Now, I hope code up the summation as follows:
m, x, y = sympy.symbols('m x y')
y = sympy.Sum(a[m]*x**m, (m, 0, 10))
But, m is not an integer so a[m] throws an Exception.
In this situation, where symbols are stored in a list, how would you code the summation? Thanks for any help!
SymPy's Sum is designed as a sum with a symbolic index. You want a sum with a concrete index running through 0, ... 9. This could be Python's sum
y = sum([a[m]*x**m for m in range(10)])
or, which is preferable from the performance point of view (relevant issue)
y = sympy.Add(*[a[m]*x**m for m in range(10)])
In either case, m is not a symbol but an integer.
I have a work-around that does not use sympy.Sum:
x = sympy.symbols('x')
y = a[0]*x**0
for i in range(1, LIMIT):
y += a[i]*x**i
This does the job, but sympy.Sum is not used.
Use IndexedBase instead of Symbol:
>>> a = IndexedBase('a')
>>> Sum(x**m*a[m],(m,1,3))
Sum(a[m]*x**m, (m, 1, 3))
>>> _.doit()
a[1]*x + a[2]*x**2 + a[3]*x**3

'int' object has no attribute '__getitem__' Python

My code is method of Euller for second ODE. I already try to do a function to define f this way
{def inicial():
global f
f=matrix(M,N)}
But I had problem in the same line. I don't know how to recognize my function in that line.
N=101
x_min = -10.0
x_max = 10.0;
dx = (x_max - x_min)/(N-1)
dt = 0.25*dx*dx
t=0
t_max = 1000
Q=1
j=0
M=2
f = [N , M]
def f_xx(i,t):
return ((f[i+1][t]-2*f[i][t]+f[i-1][t])/(dx*dx))
def guess(x):
return ((pi*Q/x_max)*x +(pi*Q))
for i in range (N):
for j in range(j):
x = x_min + i*dx
f[i][j] = guess(x)
for j in range(t_max+1):
for i in range(N-1):
x = x_min + i*dx
f[i][j+1] = f[i][j]+(f_xx(i,j)-sin(f[i][j]))*dt <<<error
for i in range (N-1):
f[i][j] = f[i][j+1]
What does mean 'int' object has no attribute getitem? Could anyone help fix it?
f is a list containing two ints. f[i] refers to the the i'th int; so f[i][j], will try and get the j'th value of an int, which cannot possibly work, whatever the value of j.
It's not clear what you are trying to do with this call, though.
You are trying to use f as a list of lists (i.e. like a 2-dimensional array), but it's really just one list: [101, 2].
I'm rusty on ODEs but I think you were trying to create a 101x2 grid of 0s. If so try f = [[0.0]*M for x in range(N)].

Categories

Resources