我是一个Prolog的总新手(如:我只用7种语言在7周内完成了Prolog章节),所以对以下任何代码的一般评论都非常受欢迎。Prolog - jigoku求解器 - 运行时间
首先:什么是jigoku?这就像一个数独,除了你得到一个空网格,并且在每个3×3的块内,给出了相邻时隙之间的不等式。示例:http://krazydad.com/jigoku/books/KD_Jigoku_CH_8_v18.pdf。您仍然需要填写网格,以便每行,每列和每个块包含数字1-9。
我试着实现一个基于这个数独求解器的求解器:http://programmablelife.blogspot.co.uk/2012/07/prolog-sudoku-solver-explained.html。为了调试原因,我开始与该作品真的很好一个4x4例如:
:- use_module(library(clpfd)).
small_jidoku(Rows, RowIneqs, ColIneqs) :-
Rows = [A,B,C,D],
append(Rows, Vs), Vs ins 1..4,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct, Columns),
blocks(A, B), blocks(C,D),
maplist(label, Rows),
fake_check_ineqs(Rows, RowIneqs),
fake_check_ineqs(Columns, ColIneqs),
pretty_print([A,B,C,D]).
blocks([], []).
blocks([A,B|Bs1], [D,E|Bs2]) :-
all_distinct([A,B,D,E]),
blocks(Bs1, Bs2).
fake_check_ineqs([],[]).
fake_check_ineqs([Head|Tail], [Ineq1|TailIneqs]) :-
Head = [A,B,C,D],
atom_chars(Ineq1, [X1,X2]),
call(X1, A, B),
call(X2, C, D),
fake_check_ineqs(Tail, TailIneqs).
pretty_print([]).
pretty_print([Head | Tail]) :-
print(Head),
print('\n'),
pretty_print(Tail).
我再解决下面的例子:
time(small_jidoku([[A1,A2,A3,A4],[B1,B2,B3,B4],[C1,C2,C3,C4],[D1,D2,D3,D4]],[><,<>,<<,<<],[><,<<,<>,>>])).
这运行在大约0.5秒上衣。不过,我也试图用它来解决它
time(small_jidoku([A,B,C,D],[><,<>,<<,<<],[><,<<,<>,>>])).
这似乎需要时间。 任何人都可以解释为什么它会花费更长的时间,当我没有指定每行有4个元素?我的天真答案是,Prolog,如果没有告诉我的行的实际格式,也会尝试探索更小/更大的行,从而浪费了时间。长度为5的行,但这是真的吗?
我的第二个问题是关于9x9版本,这非常像4x4,除了块当然更大,并且在检查不等式时还有更多的测试需要完成。代码如下:
:- use_module(library(clpfd)).
jidoku(Rows, RowIneqs, ColIneqs) :-
Rows = [A,B,C,D,E,F,G,H,I],
append(Rows, Vs), Vs ins 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct, Columns),
blocks(A, B, C), blocks(D, E, F), blocks(G, H, I),
maplist(label, Rows),
check_ineqs(Rows, RowIneqs),
check_ineqs(Columns, ColIneqs),
pretty_print([A,B,C,D,E,F,G,H,I]).
blocks([], [], []).
blocks([A,B,C|Bs1], [D,E,F|Bs2], [G,H,I|Bs3]) :-
all_distinct([A,B,C,D,E,F,G,H,I]),
blocks(Bs1, Bs2, Bs3).
check_ineqs([],[]).
check_ineqs([Head|Tail], [Ineq1|TailIneqs]) :-
Head = [A,B,C,D,E,F,G,H,I],
atom_chars(Ineq1, [X1, X2, X3, X4, X5, X6]),
call(X1, A, B),
call(X2, B, C),
call(X3, D, E),
call(X4, E, F),
call(X5, G, H),
call(X6, H, I),
check_ineqs(Tail, TailIneqs).
测试例如:
time(jidoku([[A1,A2,A3,A4,A5,A6,A7,A8,A9],
[B1,B2,B3,B4,B5,B6,B7,B8,B9],
[C1,C2,C3,C4,C5,C6,C7,C8,C9],
[D1,D2,D3,D4,D5,D6,D7,D8,D9],
[E1,E2,E3,E4,E5,E6,E7,E8,E9],
[F1,F2,F3,F4,F5,F6,F7,F8,F9],
[G1,G2,G3,G4,G5,G6,G7,G8,G9],
[H1,H2,H3,H4,H5,H6,H7,H8,H9],
[I1,I2,I3,I4,I5,I6,I7,I8,I9]],
[<>>><>,<<<>><,<<<><>,<><<><,>>><><,><>><>,<>>><>,<>><><,><<>>>],
[<<<><>,><<>>>,<><<><,><<<>>,><><<<,<><><>,<>>>><,><><><,<>><>>])).
,并没有达成任何结论,在这一点上这一个已经运行在一夜之间,我完全不知道自己什么错误。我期望一些缩放问题,但不是这个比例!
如果有人真的知道他们在做什么可以照亮这一点,那将是一件好事!谢谢!
您应该在使用标签/ 2来使用约束求解器以充分发挥其潜力前发布* all * constraints *。有关更多信息,请参阅[CLP(FD)手册](http://www.swi-prolog.org/man/clpfd.html),特别是第A.8.7节:_Enumeration谓词和search_。目前,你只使用“生成和测试”,没有太多的约束传播。 – mat
感谢您的回复!我试图将标签移动到打印之前,但是check_ineqs抱怨 2>的参数没有充分实例化。 – liesb
只需使用CLP(FD)约束'(#<)/ 2'和'(#>)/ 2'而不是更原始的算术函数。这在手册中也有例子解释。提示:'atom_chars(Atom,Cs),maplist(primitive_declarative,Cs,Ds),...'。 – mat