Finding the weighted sum of neighbours of any depth within a matrix in C

Viewed 33

I need to take a matrix as a binary file, load it in, supersize it by adding zeros around its edges then pass row by row through MPI and calculate a weighted sum of neighbours as 1/n_depth where n_depth is the distance of neighbours that needs to be summed. So for e.g.

I have a matrix generated within a binary file of any size, say 4x4.

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

This is supersized so that there are bounds.

0 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 0

Each row needs to be passed using MPI and each element position needs to sum neighours in all 8 directions by a depth of n, where only a distance of 1 is n=1 and n=2 is a distance of 2 elements.

The output matrix needs to replace each position of the input matrix by the weighted sum of neighbours.

If n=1 in this case, the first 1 you see on row 2 has a single 1 around it and therefore is the value 1 in the sum.

0 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 0

Note: italic 1 is the index position of the matrix where the sum of it's neighbours need to occur, where the bold 1 is the sum around it.

But if n=2 then we would be diagonally summing (2x1)

0 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 0

Note: italic 1 is the index position of the matrix where the sum of it's neighbours need to occur, where two diagonal bold 1s are the sum around it which equals 2.

So the if the sum of it's neighbours is 2, then the italic postion of 1 will be replaced as 2 in the output matrix.

As a caveat, I have worked out how to sum immediate neighbours where n=1 but cannot work out how to sum a distance of 2. Before coming here to reach out to the community I have attempted to give this a red hot crack and even to try and find the answer elsewhere to which I cannot find the immediate or effective answer for this scenario - really hope someone out there has done this before and can identify how to do this without complexity.

I appreciate any help to think this through.

Here is the code to generate an identity matrix like the one I presented above:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "matrix.h"

#define PERMS 0666

int main(int argc, char *argv[]){
  int fd, matrix_size, row, col;

  if((argc != 3) || 
     ((fd = creat(argv[1], PERMS)) == -1) ||
     ((matrix_size = atoi(argv[2])) <= 0)){
    
    fprintf (stderr, "Usage: %s matrix_file dimension\n", argv[0]);
    exit(1); }

  for(row = 1; row <= matrix_size; row++)
    for(col = 1; col <= matrix_size; col++)
      if(set_slot(fd,matrix_size,row,col, ((row = col) ? 1 : 0)) == -1){
        fprintf(stderr,"set_slot failed at [%d][%d]\n", row, col);
        exit(1); }
        
  fprintf (stderr, "Finished writing %s\n", argv[1]);

  return 0;

}

matrix.h:

int get_slot(int fd, int matrix_size, int row, int col, int *slot);
int set_slot(int fd, int matrix_size, int row, int col, int value);


int get_row(int fd, int matrix_size, int row, int matrix_row[]);
int set_row(int fd, int matrix_size, int row, int matrix_row[]);

int get_column(int fd, int matrix_size, int col, int matrix_col[]);

Here is the core code thus far that sums one depth:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include "mpi.h"
#include "matrix.h"
#include "matrix.c"
#define MainProcess 0
#define UseRows 3
//*****************************************************************************

//*****************************************************************************
int parse_args (int argc, char *argv[], int *fd, int *np, int *nDepth)
{
  if ((argc != 5) ||
      ((fd[0] = open (argv[1], O_RDONLY)) == -1) ||
      ((fd[1] = open (argv[2], O_WRONLY | O_CREAT, 0666)) == -1) ||
      ((*np = atoi (argv[3])) <= 0) ||
      ((*nDepth = atoi(argv[4]))<=0))
    {
      fprintf (stderr,
           "Usage: mpirun -np dimension %s matrixA matrixB dimension depth\n",
           argv[0]);
      return (-1);
    }
  return 0;
}
//*****************************************************************************

//*****************************************************************************
int main (int argc, char *argv[]) 
{
    
    int me, row, col, fd[2], i, j, nprocs, dim, K;

    //--------------------
    // Initialize MPI
    //--------------------
    MPI_Init (&argc, &argv);
    MPI_Comm_rank (MPI_COMM_WORLD, &me);
    MPI_Comm_size (MPI_COMM_WORLD, &nprocs);
     //--------------------

    if (me == MainProcess) {                
        if (parse_args (argc, argv, fd, &dim, &K) < 0) {
            MPI_Finalize ();
            exit (EXIT_FAILURE);
        }
    }

    MPI_Bcast (&dim, 1, MPI_INT, MainProcess, MPI_COMM_WORLD);

    if (dim != nprocs)
    {
        if (me == MainProcess) {
            fprintf (stderr,
            "Usage: mpirun -np dimension %s matrixA matrixB dimension depth\n",
            argv[0]);
            MPI_Finalize ();
            exit (EXIT_FAILURE);
        }
    }              

    int A[dim + 1][dim + 1], P[dim + 1][dim + 1], superA[dim + 2][dim + 2];
    int Arow[UseRows][dim + 2], Prow[dim + 2];    

    if (me == MainProcess)
    {               
        // initialize A
        for (i = 1; i < dim + 1; i++) {
            if (get_row (fd[0], dim, i, &A[i][1]) == -1)
            {
                fprintf (stderr, "Initialization of A failed\n");
                goto fail;
            }

            // initialize supersized matrix - add zeros to edges
            for (row = 0; row < dim + 2; row++) {
                superA[row][0] = superA[row][dim + 1] = 0;
            }
            for (col = 0; col < dim + 2; col++) {
                superA[0][col] = superA[dim + 1][col] = 0;
            }    
            for (row = 1; row < dim + 1; row++) {
                for (col = 1; col < dim + 1; col++) {
                    superA[row][col] = A[row][col];
                }
            }        
        }
    }

    // Scatter super sized A
    for (i = 0; i < UseRows; i++) {
        if (MPI_Scatter (&superA[i],
                dim + 2,
                MPI_INT,
                &Arow[i],
                dim + 2,
                MPI_INT, MainProcess, MPI_COMM_WORLD) != MPI_SUCCESS)
        {
            fprintf (stderr, "Scattering of A failed\n");
            goto fail;
        }
    }

    // compute my row of P - summation of neighbours at K depth
    for (i = 1; i < dim + 1; i++) {
        Prow[i] = -Arow[1][i];
        for (j = 0; j < UseRows; j++) {
            Prow[i] += Arow[j][i - 1] + Arow[j][i] + Arow[j][i + 1];
        }    
    }
    
    // Gather rows of P
    if (MPI_Gather (&Prow[0],
        dim + 1,
        MPI_INT,
        &P[1][0],
        dim + 1,
        MPI_INT, MainProcess, MPI_COMM_WORLD) != MPI_SUCCESS)
    {
        fprintf (stderr, "Gathering of Product  failed\n");
        goto fail;
    }

    // write the matrix to a file
    if (me == MainProcess)
    {
        for (i = 1; i < dim + 1; i++) {
            if (set_row (fd[1], dim, i, &P[i][1]) == -1)
            {
                fprintf (stderr, "Writing of matrix C failed\n");
                goto fail;
            }
        }    
    }

    MPI_Finalize ();
    exit (EXIT_SUCCESS);

    fail:
        fprintf (stderr, "%s aborted\n", argv[0]);
        MPI_Finalize ();
        exit (EXIT_FAILURE);                       

}
//*****************************************************************************

matrix.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int get_slot(int fd, int matrix_size, int row, int col, int *slot){
  if((row <= 0) ||
     (col <= 0) ||
     (row > matrix_size) || 
     (col > matrix_size)){
    fprintf(stderr,"indexes out of range");
    return -1; 
  } else {
    off_t offset = (((row - 1)*matrix_size) + (col - 1))*sizeof(int);
    if(offset < 0){
      fprintf(stderr,"offset overflow");
      return -1; }
    else if(lseek(fd, offset, 0) < 0){
      perror("lseek failed");
      return -1; }
    else if(read(fd, slot, sizeof(int)) < 0){
      perror("read failed");
      return -1; };
    return 0;
  }
}

int set_slot(int fd, int matrix_size, int row, int col, int value){
  if((row <= 0) ||
     (col <= 0) ||
     (row > matrix_size) || 
     (col > matrix_size)){
    fprintf(stderr,"indexes out of range");
    return -1; 
  } else {
    off_t offset = (((row - 1)*matrix_size) + (col - 1))*sizeof(int);
    if(offset < 0){
      fprintf(stderr,"offset overflow");
      return -1; }
    else if(lseek(fd, offset, 0) < 0){
      perror("lseek failed");
      return -1; }
    else if(write(fd, &value, sizeof(int)) < 0){
      perror("write failed");
      return -1; };
    return 0;
  }
}

int get_row(int fd, int matrix_size, int row, int matrix_row[]){
  int column;
  if(row > matrix_size){
    fprintf(stderr,"index out of range");
    return -1; 
  } else {
    off_t offset =  ((row - 1) * matrix_size)*sizeof(int);
    if(offset < 0){
      fprintf(stderr,"offset overflow");
      return -1; }
    else if(lseek(fd, offset, 0) < 0){
      perror("lseek failed");
      return -1; }
    else for(column = 0; column < matrix_size; column++)
      if(read(fd, &matrix_row[column], sizeof(int)) < 0){
        fprintf(stderr,"read failed column = %d\n",column);
        perror("read failed");
        return -1; };
    return 0;
  }
}

int set_row(int fd, int matrix_size, int row, int matrix_row[]){
  if(row > matrix_size){
    fprintf(stderr,"indexes out of range"); 
  return -1; 
  } else {
    int column;
    off_t offset = ((row - 1) * matrix_size)*sizeof(int);
    if(offset < 0){
      fprintf(stderr,"offset overflow");
      return -1; }
    else if(lseek(fd, offset, 0) < 0){
      perror("lseek failed");
      return -1; }
    else for(column = 0; column < matrix_size; column++)
      if(write(fd, &matrix_row[column], sizeof(int)) < 0){
        perror("write failed");
        return -1; };
    return 0;
  }
}


int get_column(int fd, int matrix_size, int col, int matrix_col[]){
  int row;
  if(col > matrix_size){
    fprintf(stderr,"index out of range");
    return -1; 
  } else {
    off_t offset;
    for(row = 1; row <= matrix_size; row++){
      offset =  ((row - 1) * matrix_size + (col - 1)) * sizeof(int);
      if(offset < 0){
        fprintf(stderr,"offset overflow");
        return -1; }
      else if(lseek(fd, offset, 0) < 0){
        perror("lseek failed");
        return -1; }
      else if(read(fd, &matrix_col[row - 1], sizeof(int)) < 0){
        fprintf(stderr,"read failed row = %d\n", row);
        perror("read failed");
        return -1; };
    }
    return 0;
  }
}
0 Answers
Related