Search code examples
carrayssimulation

Considering periodic boundary conditions when trying to find the nearest neighbors of an entry in a 2d array using the C language


Using C language, I wrote a code that gives me the eight nearest neighbors of a "site" or entry in a 2d array. The problem is that when I select an entry located on edge, I cannot obtain the correct neighbor considering the periodic boundary conditions.

The following code works perfectly when I choose an entry outside the edges:

First the program asks the user to enter the coordinates of the matrix entry, then it finds eight nearest neighbors.

//Code:
#define XMAX 3
#define YMAX 3
#define LOWER 0
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main( )
{
  
    int count = 1;
    int number;
    int x=0,y=0;
    int right, left, up, down, upleft, upright, downleft, downright;
    int grid[XMAX][YMAX];

    //Printing the matrix

    for (int i = 0; i < XMAX ; i++) {
        for (int j = 0; j < YMAX; j++) {
            grid[i][j] = count++;
            printf("%d   ", grid[i][j]);
        }
        printf("\n");
    }

   //Here I ask the user to enter the coordinates of the entry

   printf("\nEnter a X-coordinate :\n");
    scanf("%d", &y);
    printf("\nEnter a Y-coordinate :\n");
    scanf("%d", &x);
    printf("(x,y)=(%d,%d)\n",y,x); //print the chosen coordinates

   //Locating the entry of te matrix given the prior coordinates
    for (int i = 0; i < XMAX; i++)
    {
        for (int j = 0; j < YMAX; j++ )
        {
            
            if(x == i && y == j){ grid[x][y] == count; }
        }
      
    }
    
  
   //Looking up the nearest 8 neighbors (If the chosen entry is not on any edge of the matrix)
    right = grid[y][x+1];
    left = grid[y][x-1];
    up = grid[y-1][x];
    down = grid[y+1][x];
    upleft = grid[y-1][x-1];
    upright = grid[y-1][x+1];
    downleft = grid[y+1][x-1];
    downright = grid[y+1][x+1];
    
    //Considering periodic boundary conditions for the right neighbor
   if (grid[y][x] == grid[YMAX-1][x]){
        right = grid[0][x];
  }
    
     printf("The coordinates are (%d,%d) and the solicited matrix entry is: %d\n", y, x, grid[y][x]);
     
//Printing the eight nearest neighbors
     printf("Right: %d\nLeft: %d\nUp: %d\nDown: %d\nUpleft: %d\nUpright: %d\nDownleft: %d\nDownright: %d\n",right,left,up,down,upleft,upright,downleft,downright);

    return 0;
}

However when the user enters an entry located at the right edge, for example, the problem doesn't give the proper neighbor. The part of the code that should do this is:

 if (grid[y][x] == grid[YMAX-1][x]){
        right = grid[0][x];
}

But it seems the program never passes through this part of the code. I don't know what to do with this problem. Could you help me with that, please?


Solution

  • A very first change I would suggest is to avoid assigning x given by the user to a variable called y. Better keep the same name. So x is the column coordinate and y is the row coordinate, such as the notation used in math matrices.

    After this I think the biggest problem is the part the assigns the neighbor values. For instance, this:

    right = grid[y][x+1];
    

    Will go out of bounds of grid matrix when x + 1 >= XMAX

    Similarly, when x-1 < 0, this part:

    left = grid[y][x-1];
    

    Will try to access a negative index which is invalid.

    You can follow the suggestion given in a question comment to address this by using modulo or possibly creating a macro. At first I would suggest writing a simple function to handle this, such:

    int get_limited_coord(int coord, int coord_max)
    {
        if (coord >= 0 && coord < coord_max) {
    
            return coord;
    
        } else if (coord >= coord_max) {
    
            return coord - coord_max;
    
        } else {
    
            return coord + coord_max;
        }
    }
    

    And then the block that assigns these values becomes:

    right     = grid[get_limited_coord(y  , YMAX)][get_limited_coord(x+1, XMAX)];
    left      = grid[get_limited_coord(y  , YMAX)][get_limited_coord(x-1, XMAX)];
    up        = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x  , XMAX)];
    down      = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x  , XMAX)];
    upleft    = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x-1, XMAX)];
    upright   = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x+1, XMAX)];
    downleft  = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x-1, XMAX)];
    downright = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x+1, XMAX)];
    

    Would remove this block which does not seem to do anything now:

    //Locating the entry of te matrix given the prior coordinates
    for (int i = 0; i < XMAX; i++)
    {
        for (int j = 0; j < YMAX; j++ )
        {
            if(x == i && y == j){ grid[x][y] == count; }
        }
    }
    

    And ensure user input is valid:

    if (x >= XMAX || x < 0 || y >= YMAX || y < 0) {
        printf ("Invalid coordinates given\n");
        return 1;
    }
    

    Here's the code with these changes:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define XMAX 3
    #define YMAX 3
    #define LOWER 0
    
    int get_limited_coord(int coord, int coord_max)
    {
        if (coord >= 0 && coord < coord_max) {
    
            return coord;
    
        } else if (coord >= coord_max) {
    
            return coord - coord_max;
    
        } else {
    
            return coord + coord_max;
        }
    }
    
    int main( )
    {
        int count = 1;
        int number;
        int x=0,y=0;
        int right, left, up, down, upleft, upright, downleft, downright;
        int grid[XMAX][YMAX];
    
        //Printing the matrix
        for (y = 0; y < XMAX ; y++) {
            for (x = 0; x < YMAX; x++) {
                grid[y][x] = count++;
                printf("%d   ", grid[y][x]);
            }
            printf("\n");
        }
    
        //Here I ask the user to enter the coordinates of the entry
        printf("\nEnter a X-coordinate :\n");
        scanf("%d", &x);
        printf("\nEnter a Y-coordinate :\n");
        scanf("%d", &y);
        printf("(x,y)=(%d,%d)\n",x,y); //print the chosen coordinates
    
        if (x >= XMAX || x < 0 || y >= YMAX || y < 0) {
            printf ("Invalid coordinates given\n");
            return 1;
        }
    
        //Looking up the nearest 8 neighbors (If the chosen entry is not on any edge of the matrix)
        right     = grid[get_limited_coord(y  , YMAX)][get_limited_coord(x+1, XMAX)];
        left      = grid[get_limited_coord(y  , YMAX)][get_limited_coord(x-1, XMAX)];
        up        = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x  , XMAX)];
        down      = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x  , XMAX)];
        upleft    = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x-1, XMAX)];
        upright   = grid[get_limited_coord(y-1, YMAX)][get_limited_coord(x+1, XMAX)];
        downleft  = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x-1, XMAX)];
        downright = grid[get_limited_coord(y+1, YMAX)][get_limited_coord(x+1, XMAX)];
    
         printf("The coordinates are (%d,%d) and the solicited matrix entry is: %d\n", y, x, grid[y][x]);
         //Printing the eight nearest neighbors
         printf("Right: %d\nLeft: %d\nUp: %d\nDown: %d\nUpleft: %d\nUpright: %d\nDownleft: %d\nDownright: %d\n",right,left,up,down,upleft,upright,downleft,downright);
    
        return 0;
    }
    

    And a simple test:

    $ ./a.out 
    1   2   3   
    4   5   6   
    7   8   9   
    
    Enter a X-coordinate :
    0   
    
    Enter a Y-coordinate :
    2   
    (x,y)=(0,2)
    The coordinates are (2,0) and the solicited matrix entry is: 7
    Right: 8
    Left: 9
    Up: 4
    Down: 1
    Upleft: 6
    Upright: 5
    Downleft: 3
    Downright: 2