Quick start
Example
Nonograms, also known as Picross or Griddlers, are image logic puzzles in which cells in a grid must be colored or blank according to the numbers on the side of the grid to reveal a hidden image. In this type of puzzle, numbers are a form of discrete tomography that measures the number of continuous lines of filled-in squares there are in any given row or column. For example, a track of "4 8 3" would mean that there are sets of four, eight, and three filled squares, in that order, with at least one blank square between successive groups.
We can encode nonograms with BUP using the following parameters and variables defined in the viewpoint
block:
viewpoint:
param int rowSize;
param int colSize;
param int maxNonos;
param int rowNonos[rowSize][maxNonos];
param int colNonos[colSize][maxNonos];
var x[rowSize][colSize];
var hasStartedRow[rowSize][maxNonos][colSize];
var hasStartedCol[colSize][maxNonos][rowSize];
rowSize
is the grid row size.colSize
is the grid column size.maxNonos
is the maximum number of blocks that a column or a row could haverowNonos
indicates the number of blocks and its sizes in each row.colNonos
indicates the number of blocks and its sizes in each column.x
is the result board:x[i][j]
will be true if and only if rowi
, columnj
is coloured and false otherwise.hasStartedRow[i][b][j]
will be true if and only if blockb
of rowi
has already started in the columnj
.hasStartedCol[j][b][i]
will be true if blockb
of columnj
has already started in the rowi
.
The constraints are the same applied over columns and over rows. The following constrains are those applied over rows:
- If a block of a row has started at column
i
, it also must have started in columni+1
.//Order encoding forall(i in 0..rowSize-1, b in 0..maxNonos-1){ if(rowNonos[i][b] != 0){ forall(j in 0..colSize-2){ hasStartedRow[i][b][j] -> hasStartedRow[i][b][j+1]; }; } else{ &&( [!hasStartedRow[i][b][j] | j in 0..colSize-1] ); }; };
- A block mush have started soon enough to fit in the row.
forall(i in 0..rowSize-1, b in 0..maxNonos-1){ if(rowNonos[i][b] != 0){ hasStartedRow[i][b][colSize-rowNonos[i][b]]; }; };
x[i][j]
must betrue
if it is colored.//Channelling between hasStarted and x forall(i in 0..rowSize-1, b in 0..maxNonos-1){ if(rowNonos[i][b] != 0){ forall(j in 0..colSize-1){ if(j >= rowNonos[i][b]){ x[i][j] <- hasStartedRow[i][b][j] & !hasStartedRow[i][b][j-rowNonos[i][b]]; } else { x[i][j] <- hasStartedRow[i][b][j]; }; }; }; };
- The number of cells true in the row
i
must be the sum of the length of the blocks in rowi
.forall(i in 0..rowSize-1){ EK(x[i], sum(rowNonos[i])); };
- Block
b
must start before blockb+1
forall(i in 0..rowSize-1, b in 0..maxNonos-2){ if(rowNonos[i][b+1] != 0){ forall(j in 0..colSize-1){ if(j-rowNonos[i][b]-1 >= 0){ hasStartedRow[i][b+1][j] -> hasStartedRow[i][b][j-rowNonos[i][b]-1]; } else { !hasStartedRow[i][b+1][j]; }; }; }; };
Sudoku is a popular Japanese puzzle that is based on the logical placement of numbers. The goal of Sudoku is to fill in a 9×9 grid with digits so that each column, row, and 3×3 section contain the numbers between 1 to 9. At the beginning of the game, the 9×9 grid will have some of the squares filled in. Your job is to use logic to fill in the missing digits and complete the grid.
The mathematical model of the sudoku is the following:
Sets
G = Set of already placed numbers
Variables
Constraints
- Only one k in each column
- Only one k in each row
- Only one k in each sub-matrix
- Every poistion in the matrix must be filled once
- Given elements G in matrix are set “on”
A 9x9 sudoku can be modelled using BUP as:
viewpoint:
var p[9][9][9];
param int iniSudoku[9][9];
constraints:
forall(i in 0..8, j in 0..8){
EO(p[i][j][_]); // One value per cell
AMO(p[i][_][j]); // Each value one time per row
AMO(p[_][i][j]); // Each value one time per column
};
//Each value one time per block
forall(i in [0,3,6], j in [0,3,6], k in 0..8){
AMK([p[i+l][j+g][k] | l in 0..2, g in 0..2], 1);
};
//Initialize input fixed sudoku values.
forall(i in 0..8, j in 0..8){
if(iniSudoku[i][j] != 0){
p[i][j][iniSudoku[i][j]-1];
};
};
output:
"Sudoku solution: \n";
[ k+1 ++ " " ++ ((j+1) % 3 == 0 ? " " : "") ++ (j==8 ? (i+1) % 3 == 0 ? "\n\n": "\n" : "") | i in 0..8, j in 0..8, k in 0..8 where p[i][j][k]];
And the following input parameters:
{
"iniSudoku" : [
[8, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 3, 6, 0, 0, 0, 0, 0],
[0, 7, 0, 0, 9, 0, 2, 0, 0],
[0, 5, 0, 0, 0, 7, 0, 0, 0],
[0, 0, 0, 0, 4, 5, 7, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 3, 0],
[0, 0, 1, 0, 0, 0, 0, 6, 8],
[0, 0, 8, 5, 0, 0, 0, 1, 0],
[0, 9, 0, 0, 0, 0, 4, 0, 0]
]
}
The solution obtained is:
c restarts 3
c decisions 490
c propagations 108196
c conflics 291
c stats 0;0;0.043765;-1;4536;11361;3;-1;-1;490;108196;291;-1;-1;
v
s SATISFIABLE
Solució sudoku:
8 1 2 7 5 3 6 4 9
9 4 3 6 8 2 1 7 5
6 7 5 4 9 1 2 8 3
1 5 4 2 3 7 8 9 6
3 6 9 8 4 5 7 2 1
2 8 7 1 6 9 5 3 4
5 2 1 9 7 4 3 6 8
4 3 8 5 2 6 9 1 7
7 9 6 3 1 8 4 5 2