Prolog 如何优化我的数独解算器?

Prolog 如何优化我的数独解算器?,prolog,Prolog,所以我一直在尝试写一个数独解算器我写了这个: permutation([], []). permutation([X|L], P) :- permutation(L, L1), insert(X, L1, P). del(X, [X|Xs], Xs). del(X, [Y|Ys], [Y|Zs]) :- del(X, Ys, Zs). insert(X, List, BiggerList) :- del(X, BiggerList, List). block(X1,

所以我一直在尝试写一个数独解算器我写了这个:

permutation([], []).
permutation([X|L], P) :-
   permutation(L, L1),
   insert(X, L1, P).

del(X, [X|Xs], Xs).
del(X, [Y|Ys], [Y|Zs]) :-
   del(X, Ys, Zs).

insert(X, List, BiggerList) :-
   del(X, BiggerList, List).

block(X1,X2,X3,X4,X5,X6,X7,X8,X9) :-
   permutation([1,2,3,4,5,6,7,8,9],[X1,X2,X3,X4,X5,X6,X7,X8,X9]).

solveSudoku(X11,X12,X13,X14,X15,X16,X17,X18,X19,X21,X22,X23,X24,X25,X26,X27,X28,X29,X31,X32,X33,X34,X35,X36,X37,X38,X39,X41,X42,X43,X44,X45,X46,X47,X48,X49,X51,X52,X53,X54,X55,X56,X57,X58,X59,X61,X62,X63,X64,X65,X66,X67,X68,X69,X71,X72,X73,X74,X75,X76,X77,X78,X79,X81,X82,X83,X84,X85,X86,X87,X88,X89,X91,X92,X93,X94,X95,X96,X97,X98,X99) :- 
block(X11,X12,X13,X14,X15,X16,X17,X18,X19) ,
block(X21,X22,X23,X24,X25,X26,X27,X28,X29) ,
block(X31,X32,X33,X34,X35,X36,X37,X38,X39) ,
block(X41,X42,X43,X44,X45,X46,X47,X48,X49) ,
block(X51,X52,X53,X54,X55,X56,X57,X58,X59) ,
block(X61,X62,X63,X64,X65,X66,X67,X68,X69) ,
block(X71,X72,X73,X74,X75,X76,X77,X78,X79) ,
block(X81,X82,X83,X84,X85,X86,X87,X88,X89) ,
block(X91,X92,X93,X94,X95,X96,X97,X98,X99) ,
... 27 blockes
唯一的问题是,对于一个正常的输入,它永远不会完成(需要很多时间),我如何优化它? 这似乎是工作,因为当我复制它的4x4它工作得很好。对于在开始(行)检查的失败案例,它返回false


正如您所观察到的,您的程序可以很好地处理较小的问题实例,例如4x4。你看到的是搜索空间的组合爆炸。若要查看差异,请将各有4个值的4x4变量(4^16=4.29e+9个组合)与各有9个值的9x9变量(9^81=1.97e+77个组合)进行比较

block/9谓词的前9个调用构建了一个深度为81级的搜索树,同时只确保“一行中没有重复项”约束。接下来的18次block/9调用检查“column”和“block”约束,并在每次发现冲突时强制回溯到庞大的搜索树中。这是没有希望的

改进此行为的方法是在变量设置为新值后立即检查所有约束是否仍然可以满足。这实际上是约束逻辑编程的关键技术之一。几个Prolog系统支持相应的扩展(例如,请参见dif/2谓词或alldifferent/1约束)

然而,我想在这里展示一个标准Prolog程序,它实现了相同的思想。尽管它是以某种蛮力的方式实现的,但它仍然非常有效:

?- sudoku.
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[4, 5, 6, 7, 8, 9, 1, 2, 3]
[7, 8, 9, 1, 2, 3, 4, 5, 6]
[2, 1, 4, 3, 6, 5, 8, 9, 7]
[3, 6, 5, 8, 9, 7, 2, 1, 4]
[8, 9, 7, 2, 1, 4, 3, 6, 5]
[5, 3, 1, 6, 4, 2, 9, 7, 8]
[6, 4, 2, 9, 7, 8, 5, 3, 1]
[9, 7, 8, 5, 3, 1, 6, 4, 2]
Yes (0.08s cpu, solution 1, maybe more)
代码由谓词检查/1组成,确保当前变量赋值没有违反任何数独约束。每次给变量赋值时,checked_在/4之间调用此检查

sudoku :-
    Grid = [X11,X12,X13,X14,X15,X16,X17,X18,X19,
            X21,X22,X23,X24,X25,X26,X27,X28,X29,
            X31,X32,X33,X34,X35,X36,X37,X38,X39,
            X41,X42,X43,X44,X45,X46,X47,X48,X49,
            X51,X52,X53,X54,X55,X56,X57,X58,X59,
            X61,X62,X63,X64,X65,X66,X67,X68,X69,
            X71,X72,X73,X74,X75,X76,X77,X78,X79,
            X81,X82,X83,X84,X85,X86,X87,X88,X89,
            X91,X92,X93,X94,X95,X96,X97,X98,X99],

    checked_between(Grid, 1, 9, check(Grid)),

    write([X11,X12,X13,X14,X15,X16,X17,X18,X19]), nl,
    write([X21,X22,X23,X24,X25,X26,X27,X28,X29]), nl,
    write([X31,X32,X33,X34,X35,X36,X37,X38,X39]), nl,
    write([X41,X42,X43,X44,X45,X46,X47,X48,X49]), nl,
    write([X51,X52,X53,X54,X55,X56,X57,X58,X59]), nl,
    write([X61,X62,X63,X64,X65,X66,X67,X68,X69]), nl,
    write([X71,X72,X73,X74,X75,X76,X77,X78,X79]), nl,
    write([X81,X82,X83,X84,X85,X86,X87,X88,X89]), nl,
    write([X91,X92,X93,X94,X95,X96,X97,X98,X99]), nl.


% check whether any of the values chosen so far violate a sudoku constraint
check([ X11,X12,X13,X14,X15,X16,X17,X18,X19,
        X21,X22,X23,X24,X25,X26,X27,X28,X29,
        X31,X32,X33,X34,X35,X36,X37,X38,X39,
        X41,X42,X43,X44,X45,X46,X47,X48,X49,
        X51,X52,X53,X54,X55,X56,X57,X58,X59,
        X61,X62,X63,X64,X65,X66,X67,X68,X69,
        X71,X72,X73,X74,X75,X76,X77,X78,X79,
        X81,X82,X83,X84,X85,X86,X87,X88,X89,
        X91,X92,X93,X94,X95,X96,X97,X98,X99]) :-

    nodups([X11,X12,X13,X14,X15,X16,X17,X18,X19]),
    nodups([X21,X22,X23,X24,X25,X26,X27,X28,X29]),
    nodups([X31,X32,X33,X34,X35,X36,X37,X38,X39]),
    nodups([X41,X42,X43,X44,X45,X46,X47,X48,X49]),
    nodups([X51,X52,X53,X54,X55,X56,X57,X58,X59]),
    nodups([X61,X62,X63,X64,X65,X66,X67,X68,X69]),
    nodups([X71,X72,X73,X74,X75,X76,X77,X78,X79]),
    nodups([X81,X82,X83,X84,X85,X86,X87,X88,X89]),
    nodups([X91,X92,X93,X94,X95,X96,X97,X98,X99]),

    nodups([X11,X21,X31,X41,X51,X61,X71,X81,X91]),
    nodups([X12,X22,X32,X42,X52,X62,X72,X82,X92]),
    nodups([X13,X23,X33,X43,X53,X63,X73,X83,X93]),
    nodups([X14,X24,X34,X44,X54,X64,X74,X84,X94]),
    nodups([X15,X25,X35,X45,X55,X65,X75,X85,X95]),
    nodups([X16,X26,X36,X46,X56,X66,X76,X86,X96]),
    nodups([X17,X27,X37,X47,X57,X67,X77,X87,X97]),
    nodups([X18,X28,X38,X48,X58,X68,X78,X88,X98]),
    nodups([X19,X29,X39,X49,X59,X69,X79,X89,X99]),

    nodups([X11,X12,X13,X21,X22,X23,X31,X32,X33]),
    nodups([X41,X42,X43,X51,X52,X53,X61,X62,X63]),
    nodups([X71,X72,X73,X81,X82,X83,X91,X92,X93]),
    nodups([X14,X15,X16,X24,X25,X26,X34,X35,X36]),
    nodups([X44,X45,X46,X54,X55,X56,X64,X65,X66]),
    nodups([X74,X75,X76,X84,X85,X86,X94,X95,X96]),
    nodups([X17,X18,X19,X27,X28,X29,X37,X38,X39]),
    nodups([X47,X48,X49,X57,X58,X59,X67,X68,X69]),
    nodups([X77,X78,X79,X87,X88,X89,X97,X98,X99]).


nodups([]).
nodups([X|Xs]) :-
    not_contains(Xs, X),
    nodups(Xs).

not_contains([], _).
not_contains([Y|Ys], X) :-
    X \== Y,
    not_contains(Ys, X).

checked_between([], _, _, _).
checked_between([X|Xs], L, H, Check) :-
    between(L, H, X),
    call(Check),
    checked_between(Xs, L, H, Check).

between(L, H, L) :- L =< H.
between(L, H, X) :-
    L < H,
    L1 is L+1,
    between(L1, H, X).
数独:-
网格=[X11,X12,X13,X14,X15,X16,X17,X18,X19,
X21,X22,X23,X24,X25,X26,X27,X28,X29,
X31,X32,X33,X34,X35,X36,X37,X38,X39,
X41、X42、X43、X44、X45、X46、X47、X48、X49、,
X51、X52、X53、X54、X55、X56、X57、X58、X59、,
X61,X62,X63,X64,X65,X66,X67,X68,X69,
X71、X72、X73、X74、X75、X76、X77、X78、X79、,
X81,X82,X83,X84,X85,X86,X87,X88,X89,
X91、X92、X93、X94、X95、X96、X97、X98、X99],
检查(网格,1,9,检查(网格)),
写入([X11,X12,X13,X14,X15,X16,X17,X18,X19]),nl,
写入([X21,X22,X23,X24,X25,X26,X27,X28,X29]),nl,
写([X31,X32,X33,X34,X35,X36,X37,X38,X39]),nl,
写入([X41,X42,X43,X44,X45,X46,X47,X48,X49]),nl,
写入([X51、X52、X53、X54、X55、X56、X57、X58、X59]),nl,
写入([X61、X62、X63、X64、X65、X66、X67、X68、X69]),nl,
写入([X71、X72、X73、X74、X75、X76、X77、X78、X79]),nl,
写入([X81,X82,X83,X84,X85,X86,X87,X88,X89]),nl,
写入([X91、X92、X93、X94、X95、X96、X97、X98、X99]),nl。
%检查迄今为止选择的任何值是否违反数独约束
检查([X11,X12,X13,X14,X15,X16,X17,X18,X19,
X21,X22,X23,X24,X25,X26,X27,X28,X29,
X31,X32,X33,X34,X35,X36,X37,X38,X39,
X41、X42、X43、X44、X45、X46、X47、X48、X49、,
X51、X52、X53、X54、X55、X56、X57、X58、X59、,
X61,X62,X63,X64,X65,X66,X67,X68,X69,
X71、X72、X73、X74、X75、X76、X77、X78、X79、,
X81,X82,X83,X84,X85,X86,X87,X88,X89,
X91,X92,X93,X94,X95,X96,X97,X98,X99):-
节点([X11、X12、X13、X14、X15、X16、X17、X18、X19]),
节点([X21、X22、X23、X24、X25、X26、X27、X28、X29]),
节点([X31、X32、X33、X34、X35、X36、X37、X38、X39]),
节点([X41、X42、X43、X44、X45、X46、X47、X48、X49]),
节点([X51、X52、X53、X54、X55、X56、X57、X58、X59]),
节点([X61、X62、X63、X64、X65、X66、X67、X68、X69]),
节点([X71、X72、X73、X74、X75、X76、X77、X78、X79]),
节点([X81、X82、X83、X84、X85、X86、X87、X88、X89]),
节点([X91、X92、X93、X94、X95、X96、X97、X98、X99]),
节点([X11、X21、X31、X41、X51、X61、X71、X81、X91]),
节点([X12、X22、X32、X42、X52、X62、X72、X82、X92]),
节点([X13、X23、X33、X43、X53、X63、X73、X83、X93]),
节点([X14、X24、X34、X44、X54、X64、X74、X84、X94]),
节点([X15、X25、X35、X45、X55、X65、X75、X85、X95]),
节点([X16、X26、X36、X46、X56、X66、X76、X86、X96]),
节点([X17、X27、X37、X47、X57、X67、X77、X87、X97]),
节点([X18、X28、X38、X48、X58、X68、X78、X88、X98]),
节点([X19、X29、X39、X49、X59、X69、X79、X89、X99]),
节点([X11、X12、X13、X21、X22、X23、X31、X32、X33]),
节点([X41、X42、X43、X51、X52、X53、X61、X62、X63]),
节点([X71、X72、X73、X81、X82、X83、X91、X92、X93]),
节点([X14、X15、X16、X24、X25、X26、X34、X35、X36]),
节点([X44、X45、X46、X54、X55、X56、X64、X65、X66]),
节点([X74、X75、X76、X84、X85、X86、X94、X95、X96]),
节点([X17、X18、X19、X27、X28、X29、X37、X38、X39]),
节点([X47、X48、X49、X57、X58、X59、X67、X68、X69]),
节点([X77、X78、X79、X87、X88、X89、X97、X98、X99])。
节点([])。
节点([X | Xs]):-
不包含(Xs,X),
节点(Xs)。
not_包含([],u)。
不包含([Y | Ys],X):-
X\==Y,
不包含(Ys,X)。
在([]、、、、、、、、)之间选中。
检查([X | Xs],L,H,检查):-
在(L,H,X)之间,
呼叫(检查),
检查(X,L,H,检查)之间的u。
在(L,H,L)之间:-L=
从来没有,还是很久以后?(“从不”表示一个错误,逻辑上或者是由于一些内部错误造成的。)在要求优化之前,也许你应该解释一下为什么它应该工作。如果你用手写下所有无用的代码块,出错的几率是非常非常高的。。。。请把它转换成更可读的格式。很好,特别是
可能更多。仅6.67×10^21中的第一个