0

I am adapting Schorsch's answer in While loop inside for loop in Matlab to use in Python 3.5 for my problem.

I want to iterate over values in my t array. For each value, if the result of my calculation z converges (or doesn't converge after a maximum no. of iterations) I copy this to an array. Then I plot the results.

import numpy as np
import matplotlib.pyplot as plt

maxiter = 100 # max no. iterations in convergence loop
t = 0.05*np.arange(10)
z = 0.1 # initial guess
x = np.zeros(len(t)) # array for results
cvec = np.zeros(len(t)) # does loop converge?

for ii in t:

    print(ii)

    convergence = 0

    while convergence == 0:

        z_old = z
        z = ii*np.random.rand() # perform calculations

        # check convergence

        if abs(z-z_old) < 0.01: # convergence
            # store result
            convergence = 1
            x[ii] = z
            cvec[ii] = convergence

        elif abs(z-z_old) >= 0.01 and ii < maxiter: # no convergence but loop again
            convergence = 0
        else: # no convergence, move on to next value in t array
            convergence = 0
            x[ii] = 1e3
            cvec[ii] = convergence
            break

# plot result
plt.figure()
plt.plot(t[cvec==1],x[cvec==1],'x')
plt.xlabel('t')
plt.ylabel('x')
plt.show()

I get an error: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future lines = """

Does this mean I have to change how I index the while or for loops, and if so how should I do this?

Community
  • 1
  • 1
Medulla Oblongata
  • 3,771
  • 8
  • 36
  • 75
  • It probably means that you are indexing arrays using `x[ii]`, and `ii` is not an integer. Something is wrong with your `t` array (the one you use in the to iterate the for loop). If it is suppose to be integer array, but somehow is float, you can do something like `for ii in np.asarray(t, np.int32)`. – Imanol Luengo Dec 16 '16 at 10:55
  • 2
    Your question title is misleading. – Psytho Dec 16 '16 at 11:03
  • 1
    Why are you indexing with float values? I would suggest setting `x` and `cvec` to an empty list before the loops then just append the values as needed i.e. `x.append(z)`. Or, you could use a counter to index `x` and `cvec` then increment it everytime you set an element. If you need to store the time as well just set something like `timestamps = []` and append to that as well. – pbreach Dec 16 '16 at 11:03
  • @pbreach If I have a `t` array with 1000 elements say, would it be more efficient to use the `append` function or start with an array of zeros as in my MWE? – Medulla Oblongata Dec 16 '16 at 11:09
  • 1
    Actually now that I think about it the easiest way would be to just use `for idx, ii in enumerate(t):` and then just do the indexing with `idx` no need for a counter or to switch to lists :). Before I didn't realize you were storing the values for `x` in the case of non-convergence. See [here](https://docs.python.org/3/library/functions.html#enumerate) for `enumerate` function. – pbreach Dec 16 '16 at 11:14

1 Answers1

1

The issue is related with the lines x[ii] = and cvec[ii]. As you are trying to access non-integers indexes. Those indexes were generated on the following line:

(...)
t = 0.05*np.arange(10) #[ 0.  ,  0.05,  0.1 ,  0.15,  0.2 ,  0.25,  0.3 ,  0.35,  0.4 ,  0.45]
(...)

To solve the issue, there are several ways to do it, but the easiest is simply to access the same index the value from the t variable is on.

import numpy as np
import matplotlib.pyplot as plt

maxiter = 100 # max no. iterations in convergence loop
t = 0.05*np.arange(10)
z = 0.1 # initial guess
x = np.zeros(len(t)) # array for results
cvec = np.zeros(len(t)) # does loop converge?

for idx, ii in enumerate(t):

    print(ii)

    convergence = 0

    while convergence == 0:

        z_old = z
        z = ii*np.random.rand() # perform calculations

        # check convergence

        if abs(z-z_old) < 0.01: # convergence
            # store result
            convergence = 1
            x[idx] = z
            cvec[idx] = convergence

        elif abs(z-z_old) >= 0.01 and ii < maxiter: # no convergence but loop again
            convergence = 0
        else: # no convergence, move on to next value in t array
            convergence = 0
            x[idx] = 1e3
            cvec[idx] = convergence
            break

# plot result
plt.figure()
plt.plot(t[cvec==1],x[cvec==1],'x')
plt.xlabel('t')
plt.ylabel('x')
plt.show()

Using the while loop to iterate the maximum times a value, while it doesn't converge

import numpy as np
import matplotlib.pyplot as plt

maxiter = 100 # max no. iterations in convergence loop
t = 0.05*np.arange(10)
z = 0.1 # initial guess
x = np.zeros(len(t)) # array for results
cvec = np.zeros(len(t)) # does loop converge?

for idx, ii in enumerate(t):

    print(ii)

    # Assume it wont converge
    # So if we loop through all the max iterations and still no convergence, it is already marked
    x[idx] = 1e3
    cvec[idx] = 0

    while iter in range(maxiter):

        z_old = z
        z = ii*np.random.rand() # perform calculations

        if abs(z-z_old) < 0.01: # converge, therefore stop looping
            x[idx] = z
            cvec[idx] = 1
            break

# plot result
plt.figure()
plt.plot(t[cvec==1],x[cvec==1],'x')
plt.xlabel('t')
plt.ylabel('x')
plt.show()
pbreach
  • 16,049
  • 27
  • 82
  • 120
Adriano Martins
  • 1,788
  • 1
  • 19
  • 23
  • Thanks @AdrianoMartins. I think there should be a while-loop counter(https://www.tutorialspoint.com/python/python_while_loop.htm). For the line `elif abs(z-z_old) >= 0.01 and ii < maxiter: # no convergence but loop again`, we change `ii` to `counter` using the example notation in the link. – Medulla Oblongata Dec 16 '16 at 11:55
  • Updated the answer. If I managed to understand correctly, that new code should do what you're expecting – Adriano Martins Dec 16 '16 at 12:14
  • OK thanks - is the `break` command in the second code block meant to be not indented? – Medulla Oblongata Dec 16 '16 at 12:30
  • Sorry about it. I had misunderstood the issue - and made some typos. Fixed it. Now it should loop until converge or give up if the max iterations are reached. – Adriano Martins Dec 16 '16 at 12:38