Iteración de Jacobi vertical / diagonal. Versión MPI.

Sobre una matriz de números enteros, A de dimensión NxN, se realizan varias iteraciones actualizando cada elemento con la media de ese elemento con los vecinos. En las iteraciones pares se consideran sus vecinos en vertical y horizontal, y en las impares en diagonal. Se pide solución con MPI+OPENMP.


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

Parallelism parameter:

-int nodo: identificador de proceso

-int np: número total de procesos


La entrada tiene en la primera línea el número de problemas. Para cada problema hay una línea con seis valores: N, el número de iteraciones, 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

4
10 4  1 -20 20 1
920 18 2 -250 250 170
900 17 3 -200 200 107
961 20 4 -400 400 198
/*
  CPP_CONTEST=2018Enero
  CPP_PROBLEM=C
  CPP_LANG=CPP+OPENMP+MPI
  CPP_PROCESSES_PER_NODE=marte 1
*/

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

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

void filapar(int n,int *A,int *B)
{
  B[0]=(A[-n]+A[0]+A[1]+A[n])/5; //casilla izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la fila
    B[i]=(A[i-n]+A[i-1]+A[i]+A[i+1]+A[i+n])/5;
  B[n-1]=(A[-1]+A[n-2]+A[n-1]+A[2*n-1])/5; //casilla derecha
}

void filaimpar(int n,int *A,int *B)
{
  B[0]=(A[-n+1]+A[0]+A[n+1])/5; //casilla izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la fila
    B[i]=(A[i-n-1]+A[i-n+1]+A[i]+A[i+n-1]+A[i+n+1])/5;
  B[n-1]=(A[-2]+A[n-1]+A[2*n-2])/5; //casilla derecha
}

void par(int n,int *A,int *B)
{
  B[0]=(A[0]+A[1]+A[n])/5; //casilla superior-izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la primera fila
    B[i]=(A[i-1]+A[i]+A[i+1]+A[i+n])/5;
  B[n-1]=(A[n-2]+A[n-1]+A[2*n-1])/5; //casilla superior-derecha
  for(int i=1;i < n-1;i++) //para el resto de filas menos la última
    filapar(n,&A[i*n],&B[i*n]);
  B[(n-1)*n]=(A[(n-1)*n-n]+A[(n-1)*n]+A[(n-1)*n+1])/5; //casilla inferior-izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la última fila
    B[(n-1)*n+i]=(A[(n-1)*n+i-n]+A[(n-1)*n+i-1]+A[(n-1)*n+i]+A[(n-1)*n+i+1])/5;
  B[(n-1)*n+n-1]=(A[(n-1)*n-1]+A[(n-1)*n+n-2]+A[(n-1)*n+n-1])/5; //casilla inferior-derecha
}

void impar(int n,int *A,int *B)
{
  B[0]=(A[0]+A[n+1])/5; //casilla superior-izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la primera fila
    B[i]=(A[n+i-1]+A[i]+A[n+i+1])/5;
  B[n-1]=(A[2*n-2]+A[n-1])/5; //casilla superior-derecha
  for(int i=1;i < n-1;i++) //para el resto de filas menos la última
    filaimpar(n,&A[i*n],&B[i*n]);
  B[(n-1)*n]=(A[(n-1)*n]+A[(n-1)*n-n+1])/5; //casilla inferior-izquierda
  for(int i=1;i < n-1;i++) //casillas no extremas de la última fila
    B[(n-1)*n+i]=(A[(n-1)*n+i-n-1]+A[(n-1)*n+i]+A[(n-1)*n+i-n+1])/5;
  B[(n-1)*n+n-1]=(A[(n-1)*n-2]+A[(n-1)*n+n-1])/5; //casilla inferior-derecha
}

void copiar(int *vo,int n,int *vd)
{
  for(int i=0;i < n;i++)
    vd[i]=vo[i];
}

void  sec(int n,int *A,int numiter,int nodo,int np)
{
  int *B=new int[n*n];
  int numiter2=numiter/2;
  for (int i = 0; i < numiter2; i++)
  {
    par(n,A,B);
#ifdef DEBUG
  escribir(B,n,n);
#endif
    impar(n,B,A);
#ifdef DEBUG
  escribir(A,n,n);
#endif
  }
  if(numiter2*2!=numiter)
  {
    par(n,A,B);
#ifdef DEBUG
  escribir(B,n,n);
#endif
    copiar(B,n*n,A);
  }
#ifdef DEBUG
  escribir(A,n,n);
#endif
  delete[] B;
}
#include < stdlib.h >
#include < stdio.h >
#include < sys/time.h >
#include < omp.h >
#include < mpi.h >
#include < signal.h >
#include < unistd.h >

//Prueba de Metodología de la Programación Paralela
//enero 2018
//Iteración de Jacobi vertical / diagonal, versión MPI con restricción en las dimensiones 
//Esquema para entrada/salida, validación y toma de tiempos

void generar(int *m, int t,int lv,int uv) {
  int i;

  for (i = 0; i < t; i++) {
      m[i] =(int) (((1. * rand()) / RAND_MAX)*(uv-lv)+lv);
  }
}

void escribir(int *m, int N,int M) {
  int i, j;

  for (i = 0; i < N; i++) {
    for (j = 0; j < M; j++)
      printf("%d ", m[i * M + j]);
    printf("\n");
  }
  printf("\n");
}

void escribirresult(int *a,int N,int salida)
{
  int i;

  for(i=0;i < N;i++)
  {
        if((i%salida)==0)
        {
          printf("%d \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,int *A,int numiter,int nodo,int np);

int main(int argc,char *argv[]) {
  int N; //tamaño matriz
  int *A;
  int cuantos; //número de problemas
  int numiter; //número de iteraciones
  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;
  int nodo,np;

  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 */
 
  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&np);
  MPI_Comm_rank(MPI_COMM_WORLD,&nodo);
 
// The number of test cases is read
// and sent to all the processes
  if(nodo==0)
  {
    scanf("%d",&cuantos);
    MPI_Bcast(&cuantos,1,MPI_INT,0,MPI_COMM_WORLD);
  }
  else
  {
    MPI_Bcast(&cuantos,1,MPI_INT,0,MPI_COMM_WORLD);
  }

  for(int i=0;i < cuantos;i++)
  {
    if(nodo==0)
    {
       scanf("%d",&N);                   
       scanf("%d",&numiter);   
       scanf("%d",&semilla);  
       scanf("%d",&lv); 
       scanf("%d",&uv); 
       scanf("%d",&salida);  

       A = (int *) calloc(sizeof(int),N*N);

       srand(semilla);
       generar(A,N*N,lv,uv);
#ifdef DEBUG
  escribir(A,N,N);
#endif
    }
    MPI_Barrier(MPI_COMM_WORLD);
    ti=mseconds(); 
    sec(N,A,numiter,nodo,np);
    tf=mseconds(); 
    MPI_Barrier(MPI_COMM_WORLD);
    tf=mseconds(); 
    if(nodo==0)
    {
#ifdef DEBUG
  escribir(A,N,N);
#endif
      if(i!=0) tt+=tf-ti;
      escribirresult(A,N*N,salida);
      free(A);
    }
  }
  if(nodo==0)
  {   
    fprintf(stats_file, "%Ld\n", tt);
    fclose(stats_file);
  }
  MPI_Finalize();
  return 0;
}