2012-03-05 46 views
0

我想使用此代碼生成多個排列的:生成SWI-Prolog的動態大小排列結果與出錯:全球棧

:- use_module(library(clpfd)). 

p(N, Indexes) :- 
    M in 1..N, 
    M #=< N, 
    length(Indexes, M), 
    Indexes ins 1..N. 

它返回我所有的成績,但最終崩潰與ERROR: Out of global stack

+0

條件'M#= CapelliC 2012-03-05 06:55:51

+0

是的,但是使用跟蹤我看到的序言並沒有結束循環,所以我認爲這可以幫助,但它didn 't – 2012-03-05 08:48:46

回答

5

你的代碼中發生了什麼是通過調用length/2隱式設置列表的長度。這將從長度爲0的列表開始,該列表將M綁定爲0,然後依次喚醒約束M in 1..N,該約束失敗。接下來,它返回一個長度爲1的列表,該列表成功,然後在回溯長度爲2的列表中,該列表再次成功。之後,如果進一步回溯到length/2將返回更長和更長的列表,但醒來M in 1..N將始終失敗,直到列表變得如此之大以至於內存不足。

你需要做的是通過放置length/2呼叫,而不是它的內部之前的選擇點,例如,用替代

M #=< N, 

(這是一個多餘的約束反正)

indomain(M), 

這給你:

[debug] [1] ?- p(2,I). 
I = [_G3025], 
_G3025 in 1..2 ; 
I = [_G3102, _G3105], 
_G3102 in 1..2, 
_G3105 in 1..2. 

[debug] [1] ?- 
+0

謝謝,它解決了我的問題,但我不明白爲什麼;)你有任何鏈接爲什麼'M'變爲0的文檔?我也試着用'M#> ='這也是多餘的,並沒有幫助。我認爲'M ins 1..N'就像循環,但我認爲它只會在我們強迫它在域中時變成循環。 – 2012-03-05 09:06:01

+0

@Łukasz:M **從0開始**,因爲很明顯twinterer(謝謝!+1)解釋。試試這個查詢:? - length(X,Y)。 – CapelliC 2012-03-05 10:21:25

+0

@Łukasz:'M ins 1..N'不是一個循環,它是一個限制'M'的域在1和N之間的約束。作爲一個約束,它被暫停,直到M的邊界改變,當它被喚醒並檢查其一致性時。 「長度/ 2」不是一個約束,即不考慮變量「M」的域。使用無實際意義的變量調用'length/2'將會返回一個空列表。這將'M'綁定到0,這會改變'M'域的邊界,從而喚醒發佈在'M'上的約束。然後約束檢查它的一致性並失敗,因爲0不在域中。 – twinterer 2012-03-05 13:17:24

1

作爲交流者已經回答到的問題,我只需要添加一個簡單的方法來獲得(正確)排列(可能是有用的?):

permutations_n(N, P) :- 
    numlist(1, N, L), 
    permutation(L, P). 

測試:

?- permutations_n(3, X). 
X = [1, 2, 3] ; 
X = [1, 3, 2] ; 
X = [2, 1, 3] ; 
X = [2, 3, 1] ; 
X = [3, 1, 2] ; 
X = [3, 2, 1] ; 
3

它您可以通過重複排列的意思是,我不清楚。但是可能你的程序應該從between/3開始,然後包含一個all_different/1約束。

p(N, Indices) :- 
    between(1,N,M), % or maybe rather between(0,N,M). 
    length(Indices, M), 
    Indices ins 1..N, 
    all_different(Indices). 

然後,使用labeling/2來生成實際的解決方案。

+2

+1以獲得更好的解決方案,而不僅僅是修復錯誤。 (應該是'Indices ins 1..N'雖然) – twinterer 2012-03-06 07:25:01

+0

@twinterer:謝謝,修正! – false 2012-03-06 12:50:56