Multiples and divisors. MPI version

We consider a matrix of natural numbers, A, of size NxN. Each value in the matrix, A[i,j], is substituted by the sum of the values in the same row i (without considering A[i,j]) which are multiples or divisors of A minus the sum of the values in the same column j which are multiples or divisors of A.


A number of problems is solved. For each problem the function to parallelize has:

Input parameters:

-int N: for the size of the matrix

-int *A: matrix NxN of natural numbers

Files

3

3 1 1 5 1

800 4 1 20 72

750 3 2 30 67

/*
  CPP_CONTEST=2018Qual
  CPP_PROBLEM=B
  CPP_LANG=CPP+MPI
  CPP_PROCESSES_PER_NODE=1
  CPP_NUM_NODES=1
*/

#include < stdlib.h >
#include < stdio.h >
#include < omp.h >
#include < iostream >
#include < iomanip >    
#include < math.h >

using namespace std;

void copy(int n,int *vd,int *vo)
{
  for(int i=0;i < n;i++)
    vd[i]=vo[i];
}
 
void update(int n,int *a,int *b,int row,int column)
{
   int element=a[row*n+column];
   int *da=&a[row*n+column];
   int *db=&b[row*n+column];
   for(int i=1;i < n-column;i++) //the previous elements in the same row have been compared in previous calls to the routine
   {
      if(element%da[i]==0 || da[i]%element==0)
      {
        db[0]+=da[i]; 
        db[i]+=da[0];
      }
   }
   for(int i=1;i < n-row;i++) //the previous elements in the same column have been compared in previous calls to the routine
   {
      if(element%da[i*n]==0 || da[i*n]%element==0)
      {
        db[0]-=da[i*n]; 
        db[i*n]-=da[0];
      }
   }
}

void  sec(int n,int *a,int nodo,int np)
{
  int *b=(int *) calloc(sizeof(int),n*n); //to store the updated values
  for(int i=0;i < n;i++) 
  {
    for(int j=0;j < n;j++)
       update(n,a,b,i,j); 
  }
  copy(n*n,a,b);
  free(b);
}
#include < stdlib.h >
#include < stdio.h >
#include < sys/time.h >
#include < mpi.h >
#include < signal.h >
#include < unistd.h >
#include < iostream >
#include < iomanip >
#include < math.h >

using namespace std;

// Scheme for the problem of Multiples and divisors - MPI version
// Qualification contest for the Spanish Parallel Programming Contest 2018, problem B

//initialize a vector
void inicialize(int n,int *m,int lv,int uv)
{
    for(int i=0;i < n;i++)
      m[i]=int(((1.*rand())/RAND_MAX)*(uv-lv)+lv);
}

//write a matrix, only for debug
void escribir(int n,int m,int *a){
  for (int i = 0; i < n; i++)
  {
      for(int j=0;j < m;j++)
           cout << a[i*m+j]<<" ";
      cout <<endl; 
 }
  cout <<endl;
}

//output to be compared with the output of the solution provided by the organization
//only possitions multiple of step are written, to spare disk space
void escribirresult(int n,int *a,int step)
{
  for(int i=0;i < n;i++)
  {
        if((i%step)==0)
        {
          cout << a[i]<<endl;
        }
  }
}

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

//abort with the maximum execution time is reached
static void alarm_handler(int sig) {
  fprintf(stderr, "Time Limit Exceeded\n");
  abort();
}

//the external function to be parallelized by the contestants
extern void sec(int,int *,int,int);

int main(int argc,char *argv[]) {
  int num_problems; //number of problems  
  int N; //for the size of the matrix
  int *A; //matrix of data
  int seed; //seed for random generation  
  int gap; //number of data between each output (only for output)
  int lower_value;  //lower bound for the values in the vector
  int upper_value;  //upper bound for the values in the vector
  long long ti,tf,tt=0; //initial, final and total times
  int nodo,np; //number of process, and total number of processes

  FILE *stats_file = fopen("stats", "w");

//to stablish a time limit
  struct sigaction sact;
  sigemptyset(&sact.sa_mask);
  sact.sa_flags = 0;
  sact.sa_handler = alarm_handler;
  sigaction(SIGALRM, &sact, NULL);
  alarm(100);  /* 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)
  {
    cin >> num_problems;
    MPI_Bcast(&num_problems,1,MPI_INT,0,MPI_COMM_WORLD);
  }
  else
  {
    MPI_Bcast(&num_problems,1,MPI_INT,0,MPI_COMM_WORLD);
  }
  for(int i=0;i < num_problems;i++)
  {
    if(nodo==0)
    {
      cin >>N;                   // The first argument is the size of the vector
      cin >>seed; //seed for the random generation of data to generate
      cin >>lower_value;  //lower bound for the values in the vector
      cin >>upper_value;  //upper bound for the values in the vector
      cin >>gap; //gap between values to write in the output
// Space for the data
      A = new int[N*N];

      srand(seed);
      inicialize(N*N,A,lower_value,upper_value);
#ifdef DEBUG
// While debugging the vector written
      escribir(N,N,A);
#endif
    }
    MPI_Barrier(MPI_COMM_WORLD);
    ti=mseconds(); 
    sec(N,A,nodo,np);
    MPI_Barrier(MPI_COMM_WORLD);
    tf=mseconds(); 
   if(nodo==0)
    {
// The time of the first input is not considered
      if(i!=0) tt+=tf-ti;
#ifdef DEBUG
// While debugging the time of each execution is written
      fprintf(stats_file, "%Ld\n", tf-ti);
      escribir(N,N,A);
#endif
// The results of each problem are written,
// even for the first problem
      escribirresult(N*N,A,gap);
      delete[] A;
    } 
  }  

  if(nodo==0)
  { 
    fprintf(stats_file, "%Ld\n", tt);
    fclose(stats_file);
  }
  MPI_Finalize();
  return 0;
}