数独+IP+GLPK

某友人がCPLEXで数独を解いてみたと聞いて、自分でもやってみた。
01変数を9*9*9=729個使った定式化。たぶん某友人と同じ。
モデリングにはGNU MathProgを使い、ソルバはGLPKを使った。

以下のファイルを書いてから

glpsol -m sudoku.mod -d instance.dat -w result.txt

で最適化実行。
結果をawkで整形すればできあがり。

tail -n 729 result.txt | gawk '{c += $0*++i;};NR%9==0{printf("%d",c);c=0;i=0};NR%81==0{printf("\n")}'

インスタンスの出展はwikipedia:数独
計算が重ければソルバにCPLEXを使うこともできるけど、
CPLEXに比べて遅いGLPKでも一瞬で解けた。

# sudoku.mod
set I := 0..8;
set J := 0..8;
set K := 1..9;
set B := 0..8;
set Bs{b in B} := setof{y in 0..2, x in 0..2}(y+3*(b div 3),x+3*(b mod 3));

var X{I,J,K} binary;
param known{I,J}, integer;

minimize dummy: sum{i in I,j in J,k in K}X[i,j,k];
s.t. Row{i in I,k in K}: sum{j in J}X[i,j,k] = 1;
     Col{j in J,k in K}: sum{i in I}X[i,j,k] = 1;
     Cell{i in I,j in J}: sum{k in K}X[i,j,k] = 1;
     Block{b in B,k in K}: sum{(i,j) in Bs[b]}X[i,j,k] = 1;
     Known{i in I,j in J,k in K: known[i,j]==k}: X[i,j,k]=1;
# instance.dat
param known
 : 0 1 2 3 4 5 6 7 8 :=
 0 5 3 0 0 7 0 0 0 0
 1 6 0 0 1 9 5 0 0 0
 2 0 9 8 0 0 0 0 6 0
 3 8 0 0 0 6 0 0 0 3
 4 4 0 0 8 0 3 0 0 1
 5 7 0 0 0 2 0 0 0 6
 6 0 6 0 0 0 0 2 8 0
 7 0 0 0 4 1 9 0 0 5
 8 0 0 0 0 8 0 0 7 9;
# 出力
534678912
672195348
198342567
859761423
426853791
713924856
961537284
287419635
345286179