Conteo de distancias a elementos iguales en una matriz. Versiones MPI+OpenMP. Problema 1-d

Dada una matriz de caracteres, A, de dimensión NxN, se obtiene otra matriz de enteros, D, de las mismas dimensiones.

En cada posición (i,j) de D se almacena la menor distancia en A entre la posición (i,j) y otra posición con el mismo carácter A[i,j].

La distancia entre dos posiciones (x1,y1) y (x2,y2) es la distancia de Manhatan: |x2-x1|+|y2-y1|.

Cuando no hay otra posición con el mismo valor se almacena el valor cero.

Finalmente se suman todos los valores almacenados en D.

Por ejemplo, dada la matriz

aabc

cbab

bcca

accb

las distancias son

1 1 2 3

2 2 2 2

2 1 1 2

3 1 1 2

y el resultado es 28.

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

-char *A: matriz de caracteres, de dimensión NxN


Parámetros de paralelismo:

-int nodo: identificador del proceso

-int np: número total de procesos


Return:

int suma de los valores almacenados en D y calculados como se ha indicado


La entrada tiene en la primera línea el número de problemas. Para cada problema hay una línea con tres valores: N, la semilla para la generación aleatoria, número de caracteres distintos a incluir en el array.

Ficheros

3
10 1 8
5900 3 35
5500 5 37
/*
  CPP_CONTEST=2019Enero
  CPP_PROBLEM=C
  CPP_LANG=CPP+OPENMP+MPI
  CPP_PROCESSES_PER_NODE=calisto 1
*/

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

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

void distancia(int n,int row,int column, char *A,int *D)
{
    int distancia=0; //guarda la distancia, si no lo encuentra es 0
    int paso=1; //indica el paso por el que vamos
    int encontrado=0; //indica si se ha encontrado
    char elemento=A[row*n+column]; //elemento con el que vamos a comparar
    int rowact,columnizq,columnder; //en cada paso: fila actual, columnas a izquierda y derecha de la que vamos
    while(!encontrado && paso!=(2*n-1)) //hay un numero maximo de pasos. Si se encuentra se sale
    {
       for(rowact=row-paso,columnizq=column,columnder=column;!encontrado && rowact<=row;rowact++,columnizq--,columnder++)
//el paso indica cuantas filas por arriba, la primera vez estamos en la misma columna, tanto a izquierda como a derecha
//si se encuentra se acaba, o si se llega a la fila actual
//se va bajando de fila y la columna izquierda se hace una a la izquierda y la derecha una a la derecha
       {
          if((rowact>=0) && ((columnizq>=0 && elemento==A[rowact*n+columnizq]) || (columnder<n && elemento==A[rowact*n+columnder])))
//si no nos salimos de la matriz por arriba y
//no se sale la columna izquierda y coincide con el elemento, o no se sale la columna derecha y coincide con el elemento
          {
            encontrado=1;
            distancia=paso;
          }
       }
      for(rowact=row+1,columnizq=column-paso+1,columnder=column+paso-1;!encontrado && rowact<=row+paso;rowact++,columnizq++,columnder--)
//se empieza en la fila de abajo, la primera vez estamos paso-1 columnas mas a la izquierda y a la derecha
//si se encuentra se acaba, o si se llega a la fila actual mas el paso por el que vamos
//se va bajando de fila y la columna izquierda se hace una a la derecha y la derecha una a la izquierda
       {
          if((rowact<n) && ((columnizq>=0 && elemento==A[rowact*n+columnizq]) || (columnder<n && elemento==A[rowact*n+columnder])))
          {
            encontrado=1;
            distancia=paso;
          }
       }
       paso++;
    }
    D[row*n+column]=distancia;
}

void escribirint(int *m, int N,int M) {
//solo para DEBUG
  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");
}

int sumar(int n,int *m)
//suma todos los elementos del array
{
  int s=0;
  for(int i=0;i<n;i++)
    s+=m[i];
  return s;
}

int  sec(int n,char *A,int nodo,int np)
{
  int *D=(int*) calloc(sizeof(int),n*n);
  int result;
  for (int i = 0; i <n; i++)
  {
     for(int j=0;j<n;j++)
     {
        distancia(n,i,j,A,D); //calcula la distancia para cada elemento
     }
  }
#ifdef DEBUG
    escribirint(D,n,n);
#endif
  result=sumar(n*n,D);
  delete[] D;
  return result;
}
#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 2019
//Conteo de distancias a elementos iguales en una matriz
//Esquema para entrada/salida, validación y toma de tiempos

void generar(char *m, int t,int numcar) {
  int i;

  for (i = 0; i < t; i++) {
      m[i] =(char) ((int) (((1. * rand()) / RAND_MAX)*numcar)+'a');
  }
}

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

  for (i = 0; i < N; i++) {
    for (j = 0; j < M; j++)
      printf("%c", m[i * M + j]);
    printf("\n");
  }
  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 int sec(int n,char *A,int nodo,int np);

int main(int argc,char *argv[]) {
  int N; //tamaño matriz
  char *A;
  int cuantos; //número de problemas
  int semilla; //semilla para generación aleatoria
  int numcar; //número de caracteres distintos a generar
  int resul; //almacena el resultado de sec
  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(10);  /* 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",&semilla);  
      scanf("%d",&numcar); 

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

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