2011-04-11 18 views
6

Estoy tratando de transponer una matriz usando MPI en C. Cada proceso tiene una submatriz cuadrada, y quiero enviar eso al proceso correcto (el 'opuesto' en la cuadrícula), transponerlo como parte de la comunicación .¿Se puede transponer una matriz al enviar utilizando MPI_Type_create_subarray?

Estoy usando MPI_Type_create_subarray que tiene un argumento para la orden, ya sea MPI_ORDER_C o MPI_ORDER_FORTRAN para row-major y column-major, respectivamente. Pensé que si enviaba como uno de estos, y recibí como el otro, entonces mi matriz sería transpuesta como parte de la comunicación. Sin embargo, esto no parece suceder, simplemente no se transpone.

La parte importante del código está debajo, y todo el archivo de código está disponible en this gist. ¿Alguien tiene alguna idea de por qué esto no está funcionando? ¿Debería funcionar este enfoque para hacer la transposición? Lo hubiera pensado, habiendo leído las descripciones de MPI_ORDER_C y MPI_ORDER_FORTRAN, pero tal vez no.

/* ----------- DO TRANSPOSE ----------- */ 
/* Find the opposite co-ordinates (as we know it's a square) */ 
coords2[0] = coords[1]; 
coords2[1] = coords[0]; 

/* Get the rank for this process */ 
MPI_Cart_rank(cart_comm, coords2, &rank2); 

/* Send to these new coordinates */ 

tag = (coords[0] + 1) * (coords[1] + 1); 

/* Create new derived type to receive as */ 
/* MPI_Type_vector(rows_in_core, cols_in_core, cols_in_core, MPI_DOUBLE, &vector_type); */ 
sizes[0] = rows_in_core; 
sizes[1] = cols_in_core; 

subsizes[0] = rows_in_core; 
subsizes[1] = cols_in_core; 

starts[0] = 0; 
starts[1] = 0; 

MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_FORTRAN, MPI_DOUBLE, &send_type); 
MPI_Type_commit(&send_type); 

MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_DOUBLE, &recv_type); 
MPI_Type_commit(&recv_type); 


/* We're sending in row-major form, so it's just rows_in_core * cols_in_core lots of MPI_DOUBLE */ 
MPI_Send(&array[0][0], 1, send_type, rank2, tag ,cart_comm); 

/* Receive from these new coordinates */ 
MPI_Recv(&new_array[0][0], 1, recv_type, rank2, tag, cart_comm, &status); 

Respuesta

6

Pensé que esto funcionaría, también, pero aparentemente no.

Si sudar tinta a través de la relevant bit del estándar MPI donde realmente define la typemap resultante, la razón queda claro - MPI_Type_create_subarray mapas fuera de la región que lleva la submatriz de la matriz completa, pero marchas a través de la memoria en orden lineal , por lo que el diseño de los datos no cambia. En otras palabras, cuando los tamaños son iguales a los subsizes, el subarreglo es solo un bloque contiguo de memoria; y para un subcampo estrictamente más pequeño que el conjunto completo, solo está cambiando la subregión que se está enviando/recibiendo, no el ordenamiento de datos. Se puede ver el efecto de la hora de elegir sólo una subregión:

int sizes[]={cols,rows}; 
int subsizes[]={2,4}; 
int starts[]={1,1}; 

MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_FORTRAN, MPI_INT, &ftype); 
MPI_Type_commit(&ftype); 

MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &ctype); 
MPI_Type_commit(&ctype); 

MPI_Isend(&(send[0][0]), 1, ctype, 0, 1, MPI_COMM_WORLD,&reqc); 
MPI_Recv(&(recvc[0][0]), 1, ctype, 0, 1, MPI_COMM_WORLD, &statusc); 

MPI_Isend(&(send[0][0]), 1, ctype, 0, 1, MPI_COMM_WORLD,&reqf); 
MPI_Recv(&(recvf[0][0]), 1, ftype, 0, 1, MPI_COMM_WORLD, &statusf); 

/*...*/ 

printf("Original:\n"); 
printarr(send,rows,cols); 
printf("\nReceived -- C order:\n"); 
printarr(recvc,rows,cols); 
printf("\nReceived: -- Fortran order:\n"); 
printarr(recvf,rows,cols); 

le da esto:

0 1 2 3 4 5 6 
10 11 12 13 14 15 16 
20 21 22 23 24 25 26 
30 31 32 33 34 35 36 
40 41 42 43 44 45 46 
50 51 52 53 54 55 56 
60 61 62 63 64 65 66 

Received -- C order: 
    0 0 0 0 0 0 0 
    0 11 12 13 14 0 0 
    0 21 22 23 24 0 0 
    0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 

Received: -- Fortran order: 
    0 0 0 0 0 0 0 
    0 11 12 0 0 0 0 
    0 13 14 0 0 0 0 
    0 21 22 0 0 0 0 
    0 23 24 0 0 0 0 
    0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 

Así que los mismos datos se está enviado y recibido; todo lo que realmente está sucediendo es que los tamaños de los arreglos, las subscripciones y los comienzos se están revirtiendo.

Usted puede transponer con tipos de datos MPI - el estándar incluso da un couple of examples, uno de los cuales he transcrito en C aquí - pero hay que crear los tipos de sí mismo. La buena noticia es que en realidad no es más que el material de subcampo:

MPI_Type_vector(rows, 1, cols, MPI_INT, &col); 
MPI_Type_hvector(cols, 1, sizeof(int), col, &transpose); 
MPI_Type_commit(&transpose); 

MPI_Isend(&(send[0][0]), rows*cols, MPI_INT, 0, 1, MPI_COMM_WORLD,&req); 
MPI_Recv(&(recv[0][0]), 1, transpose, 0, 1, MPI_COMM_WORLD, &status); 

MPI_Type_free(&col); 
MPI_Type_free(&transpose); 

printf("Original:\n"); 
printarr(send,rows,cols); 
printf("Received\n"); 
printarr(recv,rows,cols); 



$ mpirun -np 1 ./transpose2 
Original: 
    0 1 2 3 4 5 6 
10 11 12 13 14 15 16 
20 21 22 23 24 25 26 
30 31 32 33 34 35 36 
40 41 42 43 44 45 46 
50 51 52 53 54 55 56 
60 61 62 63 64 65 66 
Received 
    0 10 20 30 40 50 60 
    1 11 21 31 41 51 61 
    2 12 22 32 42 52 62 
    3 13 23 33 43 53 63 
    4 14 24 34 44 54 64 
    5 15 25 35 45 55 65 
    6 16 26 36 46 56 66 
+0

No puedo votar esto lo suficiente. Acabo de pasar un largo viaje de ida y vuelta con un colega que ayudó a diseñar MPI-2 (!) Sobre MPI_ORDER_C frente a MPI_ORDER_FORTRAN y sus efectos. –

Cuestiones relacionadas