Code covered by the BSD License  

Highlights from
Benchmarking Sudoku Solvers

from Benchmarking Sudoku Solvers by Yi Cao
Benchmarking various sudoku solvers

[B,level,err]=yass(A,N,block)
function [B,level,err]=yass(A,N,block)
% YASS  Yet Another Sudoku Solver
% 
% Usage:    [B,level,err]=yass(A,N,block)
% Inputs:
%           A: a puzzle (9 x 9 array). 
%           N: the maximum number of solutions to seek, default N=1.
%       block: block definition for non-standard Sudoku.
% Outputs:
%           B: the solution array. For multiple solutions, B is a cell array.
%       level: the level of puzzle: 1: easy, 2: normal, 3: hard.
%         err: true if the puzzle is not valid.
%
% Example:
%{ 
% Example 1: A level-1 puzzle:
 A=[0    4    0    0    0    0    3    0    0
    0    0    2    0    0    0    0    5    0
    0    0    0    0    8    1    0    0    0
    0    0    0    0    0    0    4    1    8
    0    0    0    5    0    9    0    0    0
    0    0    0    0    0    0    0    0    6
    0    0    0    4    3    0    2    0    0
    1    0    0    0    0    0    0    0    0
    0    0    0    7    0    0    0    0    0];
[B,level]=yass(A)
%B =
%     6     4     1     9     5     7     3     8     2
%     9     8     2     3     6     4     1     5     7
%     3     7     5     2     8     1     9     6     4
%     7     5     9     6     2     3     4     1     8
%     8     1     6     5     4     9     7     2     3
%     4     2     3     1     7     8     5     9     6
5     5     9     8     4     3     6     2     7     1
%     1     3     7     8     9     2     6     4     5
%     2     6     4     7     1     5     8     3     9
%level =
%     1

% Example 2: find 100 solutions of an empty puzzle
tic,B=yass(zeros(9),100);toc
% Elapsed time is 0.866873 seconds.

% Example 3: a non-standard sudoku
block = [1  1  1  2  2  2  2  3  3
         1  1  1  2  2  3  3  3  3
         1  1  4  5  2  2  6  3  3
         1  4  4  5  5  2  6  6  3
         4  4  4  5  5  5  6  6  6
         7  4  4  5  5  8  6  6  9
         7  7  4  5  8  8  6  9  9
         7  7  7  7  8  8  8  9  9
         7  7  8  8  8  9  9  9  9];
[B,level]=yass(A,1,block)
%B =
%      8     4     1     0     5     0     3     0     0
%      0     0     2     0     4     0     1     5     0
%      0     0     0     3     8     1     0     0     0
%      0     0     0     3     0     0     4     1     8
%      0     1     0     5     0     9     0     0     3
%      0     0     0     0     0     0     0     9     6
%      0     0     8     4     3     0     2     7     1
%      1     0     0     0     9     0     0     0     0
%      0     0     0     7     1     0     9     0     0
% level =
%      1
%}
% By Yi Cao at Cranfield University on 25 Feb 2008.
%

% check inputs and outputs
error(nargchk(1,3,nargin));
error(nargoutchk(0,3,nargout));

% default setting
if nargin<2
    N=1;
end
if nargin<3,
    h = reshape(1:9,3,3);
    g = ceil((1:9)/3);
    block=h(g,g);
end

% Initialization
[I,J]=find(ones(9));
K=block(:);
B=A;
C=setC(B,I,J,K);

% Solver without recursion
[B,C,err,level]=nonrecsolver(B,C,I,J,K);
if ~any(~B(:)) || err, B=reshape(B,9,[]); return; end

% recursive solver
level=3;
B1=cell(N,1);
[B,C,err,N0,B1]=branch(B,C,I,J,K,1,B1);
B=B1(1:N0-1);
if N==1
    B=reshape(B{1},9,[]);
end    


% Basic non-recursive solver
function [B,C,err,level]=nonrecsolver(B,C,I,J,K)
% solver through finding the sole option to a grid
level=1;
[B,C,err]=findone(B,C,I,J,K);
if ~any(~B(:)) || err, return; end

% solver through finding grid pairs
level=2;
[B,C,err]=findtwo(B,C,I,J,K);

% Set grid options according to current board
function C=setC(B,I,J,K)
zB=~B;
C=false(81,9);
nc=find(~zB);
C(nc+(B(nc)-1)*81)=true;
C(zB,:)=true;
nB = nnz(B);
idxB = find(B);
for k=1:nB
    [C,err]=setOneC(C,idxB(k),I,J,K);
    if err
        return
    end
end

% update board according to grid option map C, then update C afterwards
function [B,C,err]=updateBC(B,C,I,J,K)
zB=~B;
newOne=sum(C(zB(:),:),2)==1;
err=false;
while sum(newOne)>0
    zBidx=find(zB);
    newOne=zBidx(newOne);
    [i,j]=find(C(newOne,:));
    B(newOne(i))=j;
    for k=newOne(:)'
        [C,err]=setOneC(C,k,I,J,K);
        if err
            return
        end
    end
    zB=~B;
    newOne=sum(C(zB(:),:),2)==1;
end

% set map C at grid z 
function [C,err]=setOneC(C,z,I,J,K)
zz = I==I(z) | J==J(z) | K==K(z);
zz(z) = false;
cc=C(z,:);
C(zz,cc)=false;
err=any(~any(C(zz,:),2));

% Solver through finding a grid which has a sole option
function [B,C,err]=findone(B,C,I,J,K)
flag=true;
while flag
    [B,C,err]=updateBC(B,C,I,J,K);
    if err || ~nnz(~B)
        return
    end
    [B,C,err]=findoneC(B,C,I,J,K);
    if err || ~nnz(~B)
        return 
    end
    C0=C;
    C=crosscheck(C,~B,I,J,K);
    flag=~isequal(C,C0);
end

% Sub-solver of finding sole option
function [B,C,err]=findoneC(B,C,I,J,K)
err=false;
zB=~B;
flag=1;
while any(zB(:)) && flag,
    flag=0;
    zC=reshape(find(zB),1,[]);
    for z=zC,
        is=I==I(z); is(z)=false;
        js=J==J(z); js(z)=false;
        bs=K==K(z); bs(z)=false;
        cc = C(z,:) & (~any(C(is,:)) | ~any(C(js,:)) | ~any(C(bs,:)));
        if sum(cc)==1,
            flag=1;
            ks = (is | js | bs) & zB(:);
            C(z,:)=cc;
            C(ks,cc)=false;
            if any(~any(C(ks,:),2))
                err=true;
                return
            end
            [B,C,err]=updateBC(B,C,I,J,K);
            if err
                return
            end
            zB(z)=false;
            break;
        end
    end
end

% Solver find grid pair
function [B,C,err]=findtwo(B,C,I,J,K)
C0=C;
zB=~B;
[C,err]=find2sub(C,I,zB);
if err
    return
end
[C,err]=find2sub(C,J,zB);
if err
    return
end
[C,err]=find2sub(C,K,zB);
if err
    return
end
if isequal(C0,C) 
    return, 
end;
[B,C,err]=findone(B,C,I,J,K);

% Sub-solver of finding pair
function [C,err]=find2sub(C,I,zB)
err=false;
for c=1:9,
    kc=(I==c)&zB(:);
    zc=find(kc)';
    nz=length(zc);
    if nz<4, 
        continue, 
    end
    for i=1:nz-1,
        ic=zc(i);
        kc(ic)=false;
        for j=i+1:nz,
            jc=zc(j);
            kc(jc)=false;
            cc0=C(ic,:) | C(jc,:);
            cc=cc0 & ~any(C(kc,:));
            if sum(cc)==2
                C(ic,~cc)=false;
                C(jc,~cc)=false;
                cc0=cc;
            end
            if sum(cc0)==2
                C(kc,cc0)=false;
                if any(~sum(C(kc,:),2))
                    err=true;
                    return
                end
            end
            kc(jc)=true;
        end
        kc(ic)=true;
    end
end

% Recursive solver
function [B,C,err,N,B1]=branch(B,C,I,J,K,N,B1)
C0=C;
B0=B;
sumC=sum(C,2);
sumC(B>0)=Inf;
[nz,wz]=min(sumC);
xz=find(C(wz,:));
for k=1:nz
    B(wz)=xz(k);
    C(wz,xz([1:k-1 k+1:end]))=false;
    [C,err]=setOneC(C,wz,I,J,K);
    if ~err
        [B,C,err]=nonrecsolver(B,C,I,J,K);
    end
    if ~err
        if ~any(~B(:))
            B1{N}=B;
            N=N+1;
            if N>numel(B1)
                return
            end
        else
            [B,C,err,N,B1]=branch(B,C,I,J,K,N,B1);
            if N>numel(B1)
                return
            end
        end
    end
    B=B0;
    C=C0;
end
err=true;

function [C,err]=crosscheck(C,zB,I,J,K)
err=false;
N=1:9;
I(~zB)=0;
J(~zB)=0;
K(~zB)=0;
for k=1:9
    row=false(1,9);
    col=false(1,9);
    zK = K == k;
    Ik = I(zK);
    Jk = J(zK);
    row(Ik)=true;
    col(Jk)=true;
    for r=N(row)
        rI = I == r;
        zI = zK & rI;
        kI = zK & ~rI;
        pI = rI & ~zK;
        z = any(C(zI,:),1) & ~any(C(kI,:),1);
        if sum(z)>0
            C(pI,z)=false;
            if any(~any(C(pI,:),2))
                err=true;
                return
            end
        end
        z = any(C(zI,:),1) & ~any(C(pI,:),1);
        if sum(z)>0
            C(kI,z)=false;
            if any(~any(C(kI,:),2))
                err=true;
                return
            end
        end
    end
    for c=N(col)
        cJ = J == c;
        zJ = zK & cJ;
        kJ = zK & ~cJ;
        pJ = cJ & ~zK;
        z = any(C(zJ,:),1) & ~any(C(kJ,:),1);
        if sum(z)>0
            C(pJ,z)=false;
            if any(~any(C(pJ,:),2))
                err=true;
                return
            end
        end
        z = any(C(zJ,:),1) & ~any(C(pJ,:),1);
        if sum(z)>0
            C(kJ,z)=false;
            if any(~any(C(kJ,:),2))
                err=true;
                return
            end
        end
    end
end

Contact us