fredericoamigo
fredericoamigo

Reputation: 129

IndexError trying to solve difference equations numerically in python

I'm practicing how to numerically solve difference equations, but I often run into problems like the one below.

Can anyone help me sort this out?

import numpy as np

N = 10
#alternative 1
#x = np.zeros(N+1, int)       # Produces error IndexError: index 11 is out of bounds for axis 0 with size 11

#alternative 2
x = (N+1)*[0]                 # Produces error: IndexError: list assignment index out of range

x[0] = 1000
r = 1.02

for n in range(1, N+1):
    x[n+1] = r**(n+1)*x[0]
    print(f"x[{n}] = {x[n+1]}")

Upvotes: 2

Views: 120

Answers (3)

Yahia El-Tayeb
Yahia El-Tayeb

Reputation: 146

I think your problem that you should remember the index of any element in the list starting from zero and the index of the last element is N - 1 where N is the count of the elements in the list.
So you should make this change in your for loop:

for n in range(0, N):

Also, your using of print should be a reflection to the data in your list. So you should fix the argument of your print function to the following:

print(f"x[{n+1}] = {x[n+1]}")

After making these changes, you will get this result:

x[1] = 1020.0
x[2] = 1040.4
x[3] = 1061.208
x[4] = 1082.43216
x[5] = 1104.0808032
x[6] = 1126.1624192640002
x[7] = 1148.68566764928
x[8] = 1171.6593810022657
x[9] = 1195.092568622311
x[10] = 1218.9944199947574

Please, Note you have N + 1 elements not N elements in your list because of this line of your code

x = (N+1)*[0]

Hope this help.

Upvotes: 1

Stef
Stef

Reputation: 15505

Fixing the indices

The range of your indices is inconsistent with the way you use them in the loop. You can use either of the following two possible loops, but don't mix them:

for n in range(1, N+1):
    x[n] = r**n * x[0]
for n in range(0, N):
    x[n+1] = r**(n+1) * x[0]

Optimization: multiplications instead of exponentiations

Note that computing an exponent ** is always more costly than computing a multiplication *; you can slightly optimize your code by using a recurrence formula:

for n in range(1, N+1):
    x[n] = r * x[n-1]
for n in range(0, N):
    x[n+1] = r * x[n]

Using library functions: itertools, numpy or pandas

What you are asking for is called a geometric progression. Python provides several ways of computing geometric progressions without writing the loop yourself.

For instance:

import itertools  # accumulate, repeat
import operator   # mul
def geometric_progression(x0, r, N):
    return list(itertools.accumulate(itertools.repeat(r,N), operator.mul, initial=x0))

print(geometric_progression(1000, 1.2, 10))
# [1000, 1200.0, 1440.0, 1728.0, 2073.6, 2488.3199999999997, 2985.9839999999995, 3583.180799999999, 4299.816959999999, 5159.780351999999, 6191.736422399998]

Upvotes: 1

vnk
vnk

Reputation: 1082

The length of your array is 11, which means the last element is accessed by x[10]. But in the loop, the value being called when n is 10 is x[11] which makes it go out of range.
I'm not sure about the constraints of your problem, but if you want to access x[11], change the total size of the array to x = (N+2)*[0].

Output

x[1] = 1040.4
x[2] = 1061.208
x[3] = 1082.43216
x[4] = 1104.0808032
x[5] = 1126.1624192640002
x[6] = 1148.68566764928
x[7] = 1171.6593810022657
x[8] = 1195.092568622311
x[9] = 1218.9944199947574
x[10] = 1243.3743083946524

Upvotes: 0

Related Questions