Search code examples
minizinc

A minizinc function that checks the neighbors for every element in an n*n matrix


I am trying to search for every neighbor of an element of a n*n matrix in minizinc. So far i use very in efficient way where i have if-else for the whole matrix and separate conditions to handle the boundary variables. I am kinda new to minizinc and I was hoping if there is a n efficient way to do this. maybe with a function or something.

    int: size; % Enter the size lads
 

set of int: board  = 0..size-1;


array[board,board] of var 0..1: grid;   
 
var int: z = sum(r in board, c in board) (grid[r,c]);

% solve maximize z;
solve :: int_search(
        [grid[i,j] | i,j in board],
        smallest,
        indomain_max,
        complete)
    maximize z;
 
constraint
  

  forall(r in board,c in board,x in board) (       
        if (r==0/\c==0) then           %corner 1
                      (
                           
                           if ( (grid[r,c+1] + grid[r+1,c+1]+grid[r,c+1])==3) then (grid[r,c] = 1)
                             
                              elseif(
                            (grid[r,c+1] + grid[r+1,c+1]+grid[r,c+1])  ==2)then(grid[r,c] = grid[r,c]) 
                            
                           else grid[r,c]=0 endif
                     )
                            
                            
       elseif (r==size-1/\c==size-1) then   %corner2
          (  if ((grid[r-1,c]+grid[r,c-1]+grid[r-1,c-1])==3) then  (grid[r,c] = 1)    
                         
            elseif((grid[r-1,c]+grid[r,c-1]+grid[r-1,c-1]) ==2) then (grid[r,c] = grid[r,c]) 
                          
            else (grid[r,c] = 0)   endif
           )                
       elseif (r==0/\c==size-1) then           %corner3
          (  if( (grid[r,c-1]+grid[r+1,c]+grid[r+1,c-1])==3) then (grid[r,c] = 1)   
           
             elseif((grid[r,c-1]+grid[r+1,c]+grid[r+1,c-1]) ==2)then (grid[r,c] = grid[r,c]) 
             else(grid[r,c] = 0)   endif
          )         
      elseif (r==size-1/\c==0)   then   %corner4
          (  if((grid[r-1,c]+grid[r,c+1]+grid[r-1,c+1])==3) then (grid[r,c] = 1)                  
             elseif((grid[r-1,c]+grid[r,c+1]+grid[r-1,c+1]) ==2) then  (grid[r,c] = grid[r,c]) 
             else(grid[r,c] = 0)   endif
           )              
     elseif (r==0/\c==x/\c!=0/\c!=size-1) then   %top row
          (  if((grid[r,c-1]+grid[r+1,c-1]+grid[r+1,c]+grid[r+1,c+1]+grid[r,c+1])==3) then (grid[r,c] = 1)                   
                         
             elseif((grid[r,c-1]+grid[r+1,c-1]+grid[r+1,c]+grid[r+1,c+1]+grid[r,c+1])==2 ) then (grid[r,c] = grid[r,c])   
             else(grid[r,c] = 0)   endif
           )              
     elseif (r==size-1/\c==x/\c!=0/\c!=size-1) then   %last row
          (  if((grid[r,c-1]+grid[r-1,c-1]+grid[r-1,c]+grid[r-1,c+1]+grid[r,c+1])==3) then (grid[r,c] = 1)     
             elseif((grid[r,c-1]+grid[r-1,c-1]+grid[r-1,c]+grid[r-1,c+1]+grid[r,c+1]) ==2 ) then (grid[r,c] = grid[r,c])   
             else(grid[r,c] = 0)  endif 
           )              
     elseif (r==x/\c==0/\r!=0/\r!=size-1) then   %first col
          (  if ((grid[r-1,c]+grid[r-1,c+1]+grid[r,c+1]+grid[r+1,c+1]+grid[r+1,c])==3) then (grid[r,c] = 1)   
             elseif((grid[r-1,c]+grid[r-1,c+1]+grid[r,c+1]+grid[r+1,c+1]+grid[r+1,c]) ==2) then (grid[r,c] = grid[r,c])    
             else (grid[r,c] = 0)  endif 
          )   
     
     elseif (r==x/\c==0/\r!=0/\r!=size-1) then   %last col
           ( if((grid[r-1,c]+grid[r-1,c-1]+grid[r,c-1]+grid[r+1,c-1]+grid[r+1,c])==3) then (grid[r,c] = 1)                 
             elseif((grid[r-1,c]+grid[r-1,c-1]+grid[r,c-1]+grid[r+1,c-1]+grid[r+1,c]) ==2)then(grid[r,c] = grid[r,c])   
             else(grid[r,c] = 0)   endif
           )              
       elseif (r!=0 /\ c!=x) /\ (r!=size-1/\c!=x)/\(r!=x/\c!=0)/\(r!=x/\c!=size-1) then  %rest
             (if(( grid[r-1,c-1] + grid[r-1,c] + grid[r-1,c+1] +
                          grid[r,c-1] + grid[r,c+1] +
                          grid[r+1,c-1] + grid[r+1,c] + grid[r+1,c+1]
                          )==3)then(grid[r,c] = 1)   
                   
               elseif  (( grid[r-1,c-1] + grid[r-1,c] + grid[r-1,c+1] +
                          grid[r,c-1] + grid[r,c+1] +
                          grid[r+1,c-1] + grid[r+1,c] + grid[r+1,c+1]
                          )==2 )then (grid[r,c] = grid[r,c])
                 
               else(grid[r,c] = 0)   
              endif
              ) /\       %endif  
      if (grid[r,0]==1 /\ grid[r+1,0]==1) then grid[r+2,0]=0 endif /\
   if (grid[0,c]==1 /\ grid[0,c+1]==1) then grid[0,c+2]=0 endif /\
   if (grid[size-1,c]==1 /\ grid[size-1,c+1]==1) then grid[size-1,c+2]=0 endif /\
   if (grid[r,size-1]==1 /\ grid[r+1,size-1]==1) then grid[r+2,size-1]=0 endif          
      else r=r/\c=c    
   endif             
   
  )
  /\
  forall(r in board,c in board)(
   if (grid[r,0]==1 /\ grid[r+1,0]==1) then grid[r+2,0]=0 endif /\
  if (grid[0,c]==1 /\ grid[0,c+1]==1) then grid[0,c+2]=0 endif /\
   if (grid[size,c]==1 /\ grid[size,c+1]==1/\ c<size-2/\c>1) then grid[size-1,c+2]=0 endif /\
   if (grid[r,size]==1 /\ grid[r+1,size]==1 /\ r<size-2/\r>1) then grid[r+2,size-1]=0 endif
  )

;
 
output [
  if j = 0 then "\n" else " " endif ++
   show(grid[i,j])
  | i,j in board
]
;

Solution

  • Here is a general approach of summing the neighbors of the cells (and not including "this" cell). For each cell it defines a temporary variable (t) which sums the values of the neighbor cells. You then have to add the logic for different values of t.

    int: r = 4; % rows
    int: c = 4; % column
    
    array[1..r, 1..c] of var 0..1: x;
    
    constraint
        forall(i in 1..r, j in 1..c) ( 
            let {
              var 0..r*c: t
          }
          in
           t = sum(a,b in {-1,0,1} where 
                i+a in 1..r  /\ j+b in 1..c % ensure we are in the matrix
                 /\ (a != 0 \/ b != 0) % don't include "this" cell
                ) (x[i+a,j+b])
        )
    ;
    
    solve satisfy;
    

    Update: Here's the same model with a function sum_neighbors which calculates the number of neighbors of the specific cells.

    int: r = 4; % rows
    int: c = 4; % column
    
    array[1..r, 1..c] of var 0..1: x;
    
    function var int: sum_neighbors(int: i,int: j) =
       sum(a,b in {-1,0,1} where 
             i+a in 1..r  /\ j+b in 1..c /\ (a != 0 \/ b != 0)
            ) (x[i+a,j+b])
    
    ;
    
    
    constraint
    forall(i in 1..r, j in 1..c) (
            let {
              var 0..r*c: t
          }
          in
           t = sum_neighbors(r,c)
        )
    ;
    solve satisfy;
    

    You don't have to use the temporary t variable, I added it just to be able to test the model. You can now write stuff like

    constraint
    forall(i in 1..r, j in 1..c) (
            if sum_neighbors(r,c) == 2 then
              % ...
            else
              % ...
            endif
        )
    ;