![](/img/trans.png)
[英]Prolog: calculating OEIS A031877 (“nontrivial reversal numbers”) using clp(FD)
[英]No Output in prolog Program: clp(fd) too slow
我是Prolog編程的新手,我編寫了一個代碼,用於解決4個4個魔方,但是當我運行程序時,程序沒有給出任何輸出; 它只是繼續執行(忙),最終我不得不退出SWI-Prolog。 請指導我這個問題。
碼:
:- use_module(library(clpfd)).
magic_square(Puzzle,Sum) :-
Puzzle = [S11,S12,S13,S14,
S21,S22,S23,S24,
S31,S32,S33,S34,
S41,S42,S43,S44],
Puzzle ins 1..16,
all_different(Puzzle),
labeling([],Puzzle),
R1 = [S11,S12,S13,S14], % rows
R2 = [S21,S22,S23,S24],
R3 = [S31,S32,S33,S34],
R4 = [S41,S42,S43,S44],
C1 = [S11,S21,S31,S41], % columns
C2 = [S12,S22,S32,S42],
C3 = [S13,S23,S33,S43],
C4 = [S14,S24,S34,S44],
Diag1 = [S11,S22,S33,S44], % diagonals
Diag2 = [S14,S23,S32,S41],
S11 + S12 + S13 + S14 #= Sum, % rows
S21 + S22 + S23 + S24 #= Sum,
S31 + S32 + S33 + S34 #= Sum,
S41 + S42 + S43 + S44 #= Sum,
S11 + S21 + S31 + S41 #= Sum, % columns
S12 + S22 + S32 + S42 #= Sum,
S13 + S23 + S33 + S43 #= Sum,
S14 + S24 + S34 + S44 #= Sum,
S11 + S22 + S33 + S44 #= Sum, % diagonals
S14 + S23 + S32 + S41 #= Sum.
我嘗試將sum變量更改為64,但仍然沒有任何反應。 我正在使用SWI-Prolog。
首先要做的事情!
使用clp(fd)時, 總是推遲枚舉目標,如labeling/2
直到所有約束都被陳述為止。 一般而言, 優良做法如下:
labeling/2
或其他有限域枚舉目標觸發搜索解決方案 在評論中你注意到同樣適用於3x3魔方; 當然,但它的工作並不是因為標簽的反向排序和約束 - 發布 - 盡管如此 。
你在合理的時間內得到解決方案的原因是找到大小為3x3的魔術方塊 比找到4x4方法更容易 。
因此,重新排序謂詞magicSquare4x4_withSum/2
的目標,如下所示:
:- use_module(library(clpfd)).
magicSquare4x4_withSum(Zs,Sum) :-
Zs = [S11,S12,S13,S14,
S21,S22,S23,S24,
S31,S32,S33,S34,
S41,S42,S43,S44],
Zs ins 1..16, % state the initial finite domain
S11 + S12 + S13 + S14 #= Sum, % rows
S21 + S22 + S23 + S24 #= Sum,
S31 + S32 + S33 + S34 #= Sum,
S41 + S42 + S43 + S44 #= Sum,
S11 + S21 + S31 + S41 #= Sum, % columns
S12 + S22 + S32 + S42 #= Sum,
S13 + S23 + S33 + S43 #= Sum,
S14 + S24 + S34 + S44 #= Sum,
S11 + S22 + S33 + S44 #= Sum, % diagonals
S14 + S23 + S32 + S41 #= Sum,
all_different(Zs). % no two variables shall have the same value
magicSquare4x4_withSum/2
的最一般查詢在magicSquare4x4_withSum/2
一段時間內確定性地成功; 但是,給出的答案並未顯示某些4x4魔方的具體值; 相反,它呈現了解決方案必須遵守的待決約束才能存在。
?- time(magicSquare4x4_withSum(Zs,Sum)).
% 7,780 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 8396967 Lips)
Zs = [_G9481, _G9484, _G9487, _G9490, _G9493, _G9496, _G9499, _G9502|...],
_G9481 in 1..16,
all_different([_G9481, _G9484, _G9487, _G9490, _G9493, _G9496, _G9499|...]),
_G9481+_G9496+_G9511+_G9526#=Sum,
_G9481+_G9493+_G9505+_G9517#=Sum,
_G9481+_G9484+_G9487+_G9490#=Sum,
_G9484 in 1..16,
_G9484+_G9496+_G9508+_G9520#=Sum,
_G9487 in 1..16,
_G9487+_G9499+_G9511+_G9523#=Sum,
_G9490 in 1..16,
_G9490+_G9499+_G9508+_G9517#=Sum,
_G9490+_G9502+_G9514+_G9526#=Sum,
_G9493 in 1..16,
_G9493+_G9496+_G9499+_G9502#=Sum,
_G9496 in 1..16,
_G9499 in 1..16,
_G9502 in 1..16,
_G9505 in 1..16,
_G9505+_G9508+_G9511+_G9514#=Sum,
_G9508 in 1..16,
_G9511 in 1..16,
_G9514 in 1..16,
_G9517 in 1..16,
_G9517+_G9520+_G9523+_G9526#=Sum,
_G9520 in 1..16,
_G9523 in 1..16,
_G9526 in 1..16,
Sum in 4..64.
現在,讓我們開始吧!
?- time((magicSquare4x4_withSum(Zs,Sum), labeling([],Zs))).
% 8,936,459 inferences, 1.025 CPU in 1.025 seconds (100% CPU, 8720473 Lips)
Zs = [1, 2, 15, 16, 12, 14, 3, 5, 13|...],
Sum = 34 ;
% 37,098 inferences, 0.006 CPU in 0.006 seconds (100% CPU, 6073990 Lips)
Zs = [1, 2, 15, 16, 13, 14, 3, 4, 12|...],
Sum = 34 % and the search goes on...
我們可以做些什么來加速搜索? 首先,我們嘗試不同的標簽啟發式/選項。
?- time((magicSquare4x4_withSum(Zs,Sum), labeling([ff],Zs))).
% 5,056,298 inferences, 0.578 CPU in 0.578 seconds (100% CPU, 8749040 Lips)
Zs = [1, 2, 15, 16, 12, 14, 3, 5, 13|...],
Sum = 34 ;
% 36,783 inferences, 0.006 CPU in 0.006 seconds (100% CPU, 5733914 Lips)
Zs = [1, 2, 15, 16, 13, 14, 3, 4, 12|...],
Sum = 34 % and the search goes on...
我們還能做什么? 通過提供總和作為常量來幫助搜索。
?- time((magicSquare4x4_withSum(Zs,34), labeling([],Zs))).
% 106,296 inferences, 0.017 CPU in 0.017 seconds (100% CPU, 6242045 Lips)
Zs = [1, 2, 15, 16, 12, 14, 3, 5, 13|...] ;
% 36,858 inferences, 0.009 CPU in 0.009 seconds (100% CPU, 4076658 Lips)
Zs = [1, 2, 15, 16, 13, 14, 3, 4, 12|...] ;
% 209,206 inferences, 0.028 CPU in 0.028 seconds (100% CPU, 7430044 Lips)
Zs = [1, 2, 16, 15, 13, 14, 4, 3, 12|...] % and the search goes on...
性能方面,a-priori將總和約束為值34具有重大影響!
我們還能做什么?
我們可以通過排除僅僅是“翻轉”或“旋轉” 的解決方案來添加限制搜索和解決方案空間的其他約束 。
讓我們考慮大小為3x3的魔方:有8個不同的,但實際上它們都是同一魔方的“翻轉”/“旋轉”。 在這8個中,我們可以在知道如何構造它們時安全地消除7個。
破壞對稱性限制了搜索空間和解空間的大小,我們可以通過使用魔方的四個角之間的排序約束來表達它:
magicSquare4x4withRestrictedSymmetries(Zs) :-
Zs = [S11,_,_,S14,
_,_,_,_,
_,_,_,_,
S41,_,_,S44],
S11 #< S14,
S11 #< S44,
S11 #< S41,
S14 #< S41.
這些額外的約束可能會或可能不會幫助我們更快地找到第一個解決方案 ,但它們肯定有助於搜索所有解決方案 。
首先,讓我們在沒有破壞對稱性的附加約束的情況下這樣做:
?- time((findall(t,(magicSquare4x4_withSum(Zs,34),
labeling([ff],Zs)),Ts),
length(Ts,N_Sols))).
% 1,526,766,108 inferences, 152.1 CPU in 152.1 seconds (100% CPU, 10033768 Lips)
Ts = [t, t, t, t, t, t, t, t, t|...],
N_Sols = 7040.
現在,有了額外的限制:
?- time((findall(t,(magicSquare4x4_withSum(Zs,34),
magicSquare4x4withRestrictedSymmetries(Zs),
labeling([ff],Zs)),Ts),
length(Ts,N_Sols))).
% 129,527,384 inferences, 12.580 CPU in 12.578 seconds (100% CPU, 10295893 Lips)
Ts = [t, t, t, t, t, t, t, t, t|...],
N_Sols = 880.
大贏! 搜索所有解決方案的速度要快10倍以上。 正如所料,當破壞對稱性時,解決方案的數量精確地除以8(880 * 8 = 7040)。 HTH!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.