Ordenación de filas y columnas y suma. Versión OpenMP con paralelismo anidado.

Se trabaja sobre una matriz de números reales, A de dimensión NxN. Se genera una matriz F, NxN, con cada fila la fila correspondiente de A con los datos ordenados de menor a mayor, y otra matriz C, NxN, con cada columna la columna correspondiente de A con los datos ordenados de menor a mayor. Finalmente se actualiza A=F+C.

Se resuelven varios problemas. Para cada problema la función a paralelizar tiene parámetros:

Input parameter:

int N: número de filas y columnas

Input/Output parameter:

double *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 de datos, los valores mínimo y máximo para la generación, y un valor que indica cada cuantos elementos se escribe un elemento a la salida.

Ficheros

3
10 4 -20 20 1
1300 18  -250 250 370
1700 17  -200 200 907
/*
  CPP_CONTEST=2018Junio
  CPP_PROBLEM=C
  CPP_LANG=CPP+OPENMP
  CPP_PROCESSES_PER_NODE=calisto 1
*/

#include < stdlib.h >
#include < omp.h >

extern void escribir(double *,int,int);

void copiar(int n,double *vd,int ldvd,double *vo,int ldvo) 
//se copia el vector vo en el vd
//como los datos pueden no estar contiguos se accede a ellos con los ld
{
  int i;
  for(i=0;i < n;i++)
    vd[i*ldvd]=vo[i*ldvo];
}

void ordenar(int n,double *m)
{
  int i,j;
  double t;
  for(i=0;i < n;i++)
    for(j=i+1;j < n;j++)
    {
      if(m[i] > m[j])
      {
        t=m[i];
        m[i]=m[j];
        m[j]=t;
      }
    }
}

void ordenarfilas(int n,double *A,double *F)
{
  int i;
  for(i=0;i < n;i++)
  { 
    copiar(n,&F[i*n],1,&A[i*n],1); //se copia la fila de A en la correspondiente de F
    ordenar(n,&F[i*n]); //y se ordena la fila en F
  }
}

void trasponer(int n,double *m)
{
  int i,j;
  double t;
  for(i=0;i < n;i++)
    for(j=i+1;j < n;j++)
    {
       t=m[i*n+j];
       m[i*n+j]=m[j*n+i];
       m[j*n+i]=t;
    }
}

void ordenarcolumnas(int n,double *A,double *C)
{
  int i;
  for(i=0;i < n;i++)
  { 
    copiar(n,&C[i*n],1,&A[i],n); //se copia la columna de A en la fila correspondiente de C
    ordenar(n,&C[i*n]); //y se ordena la fila en C
  }
  trasponer(n,C); //se pasan las filas de C, que tienen las columnas ordenadas de A, a las columnas correspondientes
}

void sumar(int n,double *vd,double *vo1,double *vo2)
{
  int i;
  for(i=0;i < n*n;i++)
    vd[i]=vo1[i]+vo2[i];
}

void  sec(int n,double *A)
{
  double *F=new double[n*n];
  double *C=new double[n*n];
  
  ordenarfilas(n,A,F);
#ifdef DEBUG
  escribir(F,n,n);
#endif
   ordenarcolumnas(n,A,C);
#ifdef DEBUG
  escribir(C,n,n);
#endif
  sumar(n,A,F,C);
#ifdef DEBUG
  escribir(A,n,n);
#endif
  delete[] F;
  delete[] C;
}
#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
//junio 2018
//Ordenación de filas y columnas y suma. Versión OpenMP con paralelismo anidado
//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("%.6lf ", 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("%.10lf \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;
}