我正在尝试使用以下代码生成多个排列:
:- 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
您的代码中发生的情况是列表的长度是通过调用隐式设置的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] ?-
我不清楚你所说的多重排列是什么意思。但可能你的程序应该从一个约束开始,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
生成实际解决方案。
由于 twinterer 已经回答了问题,我只是添加了一种更简单的方法来获得(正确的)排列(可能有用吗?):
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] ;