Multiplicación de matrices incremental. Versión OpenMP.

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.

Ficheros

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;
}

#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;
}