我是一個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