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
]
;
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
)
;