0

EDIT: I have changed my code below presenting the working version, thanks to @hpaulj

I am trying to solve the 2D Laplace equation using Gauss-Seidel iteration: every non-boundary element in the matrix is replaced by the average of the surrounding matrix elements. I first create the basic matrix.

# creation of matrix using random values and boundary conditions.
matrix = np.random.random((4,4))
for n in range(4): matrix.itemset((4-1, n), 10)
for n in range(4): matrix.itemset((n, 4-1), 0)
for n in range(4): matrix.itemset((0, n), 0)
for n in range(4): matrix.itemset((n, 0), 0)

Output:

[[ 0.          0.          0.          0.        ]
 [ 0.          0.33285936  0.59830215  0.        ]
 [ 0.          0.07021714  0.45341002  0.        ]
 [ 0.         10.         10.          0.        ]]

Using the following code snippet, I try to find the left, right, up and down element around each non-boundary element in my array.

# opening the matrix and preparing it to be read and rewritten.
#with np.nditer(matrix, op_flags=['readwrite']) as it:
with np.nditer(matrix, op_flags=['readwrite'], flags=['multi_index']) as it:

    # loop to find each element in our matrix
    #for index, x in np.ndenumerate(matrix):
    for x in it:
        #row, colum = index

        # only non-border values may be adjusted
        if x != 0 and x != 10:
            row, colum = it.multi_index

            # finding each element around x
            left = matrix[row][colum-1]
            right = matrix[row][colum+1]
            up = matrix[row-1][colum]
            down = matrix[row+1][colum]

            # finding average of elements around x
            newvalue = 1/4*(left+right+up+down)
            x[...] = newvalue

Instead of replacing the values, python prints out the following error:

x[...] = newvalue
TypeError: 'numpy.float64' object does not support item assignment

I don't get the error if I just use

for x in it:

but then I cannot keep track of the x, y values in my array. Does anybody know how to keep track of the position of the element or resolve the error?

6
  • x in the iteration is the value at slot in matrix, but it is not a reference to that slot. As the error says, it's a number. matrix[row, col] = newvalue should work. Commented Apr 15, 2020 at 20:31
  • The iteration variable for nditer is a reference to the slot, a 0d array. x[...]=newvalue does work for that. Do a print(type(x)) in both loops to see the difference. There's no point in nesting the ndenumerate(matrix) loop inside the nditer context. Commented Apr 15, 2020 at 20:34
  • There is a multi-index option in nditer if you want to track row/col, numpy.org/devdocs/reference/… Commented Apr 15, 2020 at 20:37
  • I suspect this code would run faster if you used nested lists instead of an array. You aren't make much (if any) use of numpy array methods. List iteration is faster (and nditer does not help!). Commented Apr 15, 2020 at 20:39
  • @hpaulj I thought numpy arrays would be faster. This array is currently very small, but for the final program, it will be 100×100 large. Will nested loops still be faster? Commented Apr 15, 2020 at 20:50

1 Answer 1

1

Better use of numpy index to set the matrix:

In [358]: arr = np.random.random((4,4))                                                                
In [359]: arr[[0,3],:] = 0                                                                             
In [360]: arr[:,[0,3]] = 0                                                                             
In [361]: arr[3,1:-1] = 10                                                                             
In [362]: arr                                                                                          
Out[362]: 
array([[ 0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.8869947 ,  0.61765067,  0.        ],
       [ 0.        ,  0.92640868,  0.83014953,  0.        ],
       [ 0.        , 10.        , 10.        ,  0.        ]])

or even:

In [363]: arr = np.zeros((4,4))                                                                        
In [364]: arr[1:-1,1:-1] = np.random.random((4-2,4-2))                                                 
In [365]: arr                                                                                          
Out[365]: 
array([[0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.50803298, 0.78055366, 0.        ],
       [0.        , 0.98941105, 0.61842531, 0.        ],
       [0.        , 0.        , 0.        , 0.        ]])

I suspect your other iteration can be rewritten to make good use of array methods, but I won't tackle that now.

Here's the difference that I mentioned in the comments:

In [367]: with np.nditer(arr, op_flags=['readwrite']) as it: 
     ...:    for x in it: 
     ...:        print(type(x), x) 
     ...:                                                                                              
<class 'numpy.ndarray'> 0.0
<class 'numpy.ndarray'> 0.0
<class 'numpy.ndarray'> 0.0
...
In [368]: for index,x in np.ndenumerate(arr): 
     ...:     print(type(x),x) 
     ...:                                                                                              
<class 'numpy.float64'> 0.0
<class 'numpy.float64'> 0.0
<class 'numpy.float64'> 0.0
....

and the use of multi_Index:

In [369]: with np.nditer(arr, op_flags=['readwrite'],flags=['multi_index']) as it: 
     ...:    for x in it: 
     ...:        print(type(x), x, it.multi_index) 
     ...:                                                                                              
<class 'numpy.ndarray'> 0.0 (0, 0)
...
<class 'numpy.ndarray'> 0.5080329836279988 (1, 1)
<class 'numpy.ndarray'> 0.7805536642151875 (1, 2)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the suggestion.
I am not too concerned about speed. The code is working thanks to your suggestions. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.