Sobre una matriz de números reales, A de dimensión NxN, se realizan las multiplicaciones: de la submatriz 1x1 de la parte superior-izquierda por sí misma, de la submatriz 2x2 de la parte superior-izquierda por sí misma..., y así sucesivamente hasta la matriz completa NxN. Las multiplicaciones son independientes, sin sustituir las entradas de la matriz original A tras cada multiplicación. Finalmente se suman todas las matrices obtenidas, acumulando los resultados de cada matriz en sus posiciones correspondientes de la matriz A. El código secuencial que se proporciona no está optimizado (se podría reutilizar información de una multiplicación para la siguiente) y no se pide optimizarlo en secuencial, sino simplemente paralelizarlo, en este caso con OpenMP. Se valorarán más soluciones que exploten paralelismo de grano grueso.
Se resuelven varios problemas. Para cada problema la función a paralelizar tiene parámetros:
Input parameters:
-int N: número de filas y columnas
Input/Output parameter:
-int *A: matriz de dimensión NxN
La entrada tiene en la primera línea el número de problemas. Para cada problema hay una línea con cinco valores: N, la semilla para la generación aleatoria, los valores mínimo y máximo para la generación, y un valor que indica cada cuantos elementos se escribe uno a la salida.
3 10 1 -1 1 1 400 2 -1 1 130 430 3 -1 1 210
/* CPP_CONTEST=2018Enero CPP_PROBLEM=D CPP_LANG=CPP+OPENMP CPP_PROCESSES_PER_NODE=jupiter 1 */ #include < stdlib.h> #include < omp.h> extern void escribir(double *,int,int); void multiplicar(int n,int ld,double *a,double *r) { for(int i=0;i < n;i++) { for(int j=0;j < n;j++) { double s=r[i*ld+j]; for(int k=0;k < n;k++) { s+=a[i*ld+k]*a[k*ld+j]; } r[i*ld+j]=s; } } } void copiar(double *vo,int n,double *vd) { for(int i=0;i < n;i++) vd[i]=vo[i]; } void sec(int n,double *A) { double *R=new double[n*n]; for(int i=0;i < n*n;i++) R[i]=0.; for (int i = 0; i < n; i++) { multiplicar(i+1,n,A,R); } copiar(R,n*n,A); #ifdef DEBUG escribir(R,n,n); #endif delete[] R; }
esquema-openmp.cpp (no modificable, lo usa mooshak para entrada/salida y evaluación, se proporciona para experimentación en local)
#include < stdlib.h> #include < stdio.h> #include < sys/time.h> #include < omp.h> #include < signal.h> #include < unistd.h> //Prueba de Metodología de la Programación Paralela //enero 2018 //Multiplicación de matrices incremental, versión OpenMP //Esquema para entrada/salida, validación y toma de tiempos void generar(double *m, int t,int lv,int uv) { int i; for (i = 0; i < t; i++) { m[i] =(((1. * rand()) / RAND_MAX)*(uv-lv)+lv); } } void escribir(double *m, int N,int M) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < M; j++) printf("%.3lf ", m[i * M + j]); printf("\n"); } printf("\n"); } void escribirresult(double *a,int N,int salida) { int i; for(i=0;i < N;i++) { if((i%salida)==0) { printf("%.3lf \n",a[i]); } } printf("\n"); } /* c c mseconds - returns elapsed milliseconds since Jan 1st, 1970. c */ long long mseconds(){ struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } static void alarm_handler(int sig) { fprintf(stderr, "Time Limit Exceeded\n"); abort(); } extern void sec(int n,double *A); int main(int argc,char *argv[]) { int N; //tamaño matriz double *A; int cuantos; //número de problemas int semilla; //semilla para generación aleatoria int lv,uv; //valores inferior y superior para generación aleatoria int salida; //indica cada cuantos elementos se escribe uno a la salida long long ti,tf,tt=0; FILE *stats_file = fopen("stats", "w"); struct sigaction sact; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = alarm_handler; sigaction(SIGALRM, &sact, NULL); alarm(60); /* time limit */ scanf("%d",&cuantos); for(int i=0;i < cuantos;i++) { scanf("%d",&N); scanf("%d",&semilla); scanf("%d",&lv); scanf("%d",&uv); scanf("%d",&salida); A = (double *) calloc(sizeof(double),N*N); srand(semilla); generar(A,N*N,lv,uv); #ifdef DEBUG escribir(A,N,N); #endif ti=mseconds(); sec(N,A); tf=mseconds(); #ifdef DEBUG escribir(A,N,N); #endif if(i!=0) tt+=tf-ti; escribirresult(A,N*N,salida); free(A); } fprintf(stats_file, "%Ld\n", tt); fclose(stats_file); return 0; }