pythonmatrixparallel-processingmpimpi4py

MPI4PY: Scatter a matrix


I am using MPI4PY to scatter n/p columns to two input data processes. However, I am unable to send the columns as I would like. What changes do I have to make to the code in order to get the result reported in the final comment?

The matrix is:

[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14, 15, 16]

Then, n=4 and p=2. Each process will have 2 columns respectively.

This is my code:

# Imports
from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD
size = comm.Get_size() 
rank = comm.Get_rank()

rows = 4
num_columns = rows/size

data=None

if rank == 0:
  data = np.matrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])

recvbuf = np.empty((rows, int(num_columns)), dtype='int')
comm.Scatterv(data, recvbuf, root=0)
print('Rank: ',rank, ', recvbuf received:\n ',recvbuf)

I get the following output:

Rank:  0 , recvbuf received:
[[1 2]
[3 4]
[5 6]
[7 8]]
Rank:  1 , recvbuf received:
[[ 9 10]
[11 12]
[13 14]
[15 16]]

I want to get the following output instead:

Rank:  0 , recvbuf received:
[[1 2]
[5 6]
[9 10]
[13 14]]
Rank:  1 , recvbuf received:
[[ 3 4]
[7 8]
[11 12]
[15 16]]

Solution

  • I think this code does what you are looking for. The issue here is that Scatterv doesn't care about numpy array shape at all, it just considers a linear block of memory containing your values. Therefore, the simplest approach is to manipulate your data into the correct order beforehand. Note that send_data is a 1D array, but this doesn't matter because Scatterv doesn't care. At the other end, the shape of recvbuf is already defined, and Scatterv just fills it up from the 1D input received.

    # Imports
    from mpi4py import MPI
    import numpy as np
    
    comm = MPI.COMM_WORLD
    size = comm.Get_size()
    rank = comm.Get_rank()
    
    rows = 4
    num_cols = rows/size
    
    send_data=None
    
    if rank == 0:
      data = np.matrix([[1, 2, 3, 4],
                        [5, 6, 7, 8],
                        [9, 10, 11, 12],
                        [13, 14, 15, 16]])
    
      # Split into sub-arrays along required axis
      arrs = np.split(data, size, axis=1)
    
      # Flatten the sub-arrays
      raveled = [np.ravel(arr) for arr in arrs]
    
      # Join them back up into a 1D array
      send_data = np.concatenate(raveled)
    
    
    recvbuf = np.empty((rows, int(num_cols)), dtype='int')
    comm.Scatterv(send_data, recvbuf, root=0)
    
    print('Rank: ',rank, ', recvbuf received:\n ',recvbuf)