让 Prolog 的 CLPFD 知道排列和其他对称性
Making Prolog's CLPFD aware of permutations and other symmetries
use_module(library(clpfd)).
CLPFD 似乎并没有很快意识到
length(L, 9), L ins 1..9, all_distinct(L), foreach(label(L), sum(L, #=, X))
X=45.
(我试过 length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]).
试图通知我 1 + 2 + 3 + 4 = 7
,所以我可能误解了什么)。
length(L, 9), L ins 1..9, all_distinct(L), bagof(L, label(L), Ls), length(Ls, X).
应该给哪位X = 362880.
也有类似问题
两者似乎都在 O(N!) 中执行 length(L, N)
,这当然是因为我们正在枚举
L
的每一种可能的排列来得出我们的结论。
这些边缘情况当然可以用更简单的解决方案代替,我们可以在任何地方使用它们。
但是例如,如果能够让 CLPFD 能够推断出
length(L, N - 1), L ins 1..N, all_distinct(L)
我们可以计算 sum(L, #=, X)
得到 X in N (N - 1) / 2 - N..N (N - 1) / 2 - 1
.
我是否遗漏了 CLPFD 的某些方面或计算标签而不枚举它们的谓词,
以及一种让 CLPFD 了解 sum
的鸽巢原理 + 结合性 + 交换性的方法,
还是为这些特定情况编写谓词?
在 SWI Prolog 8.1 中:
我不太了解你似乎 "label" 太早或太急切("foreach of the labelings" 闻起来有鱼腥味)
尝试
?- length(L, 9), L ins 1..9, all_distinct(L), sum(L, #=, X), X = 45, label(L).
立即returns与
L = [1, 2, 3, 4, 5, 6, 7, 8, 9],
X = 45
类似于
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label(L).
这给出了
L = [1, 2, 3, 4],
X = 10 ;
我不确定这里发生了什么,但再次 label([X])
听起来不对。
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]).
L = [_7950, _7956, _7962, _7968],
X = 7,
_7950 in 1..4,
_7950+_7956+_7962+_7968#=7,
all_distinct([_7950, _7956, _7962, _7968]),
_7956 in 1..4,
_7962 in 1..4,
_7968 in 1..4 ;
我确实认为 CLP(FD) 没有注意到上面的解决方案没有解决方案,因为它只输出约束。
但是试试
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]), label(L).
L = [1, 2, 3, 4],
X = 10
正确。
But for example it would be nice to be able have CLPFD be able to reason that in length(L, N - 1), L ins 1..N, all_distinct(L) we can calculate sum(L, #=, X) to have X in N (N - 1) / 2 - N..N (N - 1) / 2 - 1.
证明整数算术的绝对一般定理,而不是约束传播。那会很好,但我认为它不会走那么远。
use_module(library(clpfd)).
CLPFD 似乎并没有很快意识到
length(L, 9), L ins 1..9, all_distinct(L), foreach(label(L), sum(L, #=, X))
X=45.
(我试过 length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]).
试图通知我 1 + 2 + 3 + 4 = 7
,所以我可能误解了什么)。
length(L, 9), L ins 1..9, all_distinct(L), bagof(L, label(L), Ls), length(Ls, X).
应该给哪位X = 362880.
也有类似问题
两者似乎都在 O(N!) 中执行 length(L, N)
,这当然是因为我们正在枚举
L
的每一种可能的排列来得出我们的结论。
这些边缘情况当然可以用更简单的解决方案代替,我们可以在任何地方使用它们。
但是例如,如果能够让 CLPFD 能够推断出
length(L, N - 1), L ins 1..N, all_distinct(L)
我们可以计算 sum(L, #=, X)
得到 X in N (N - 1) / 2 - N..N (N - 1) / 2 - 1
.
我是否遗漏了 CLPFD 的某些方面或计算标签而不枚举它们的谓词,
以及一种让 CLPFD 了解 sum
的鸽巢原理 + 结合性 + 交换性的方法,
还是为这些特定情况编写谓词?
在 SWI Prolog 8.1 中:
我不太了解你似乎 "label" 太早或太急切("foreach of the labelings" 闻起来有鱼腥味)
尝试
?- length(L, 9), L ins 1..9, all_distinct(L), sum(L, #=, X), X = 45, label(L).
立即returns与
L = [1, 2, 3, 4, 5, 6, 7, 8, 9],
X = 45
类似于
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label(L).
这给出了
L = [1, 2, 3, 4],
X = 10 ;
我不确定这里发生了什么,但再次 label([X])
听起来不对。
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]).
L = [_7950, _7956, _7962, _7968],
X = 7,
_7950 in 1..4,
_7950+_7956+_7962+_7968#=7,
all_distinct([_7950, _7956, _7962, _7968]),
_7956 in 1..4,
_7962 in 1..4,
_7968 in 1..4 ;
我确实认为 CLP(FD) 没有注意到上面的解决方案没有解决方案,因为它只输出约束。
但是试试
?- length(L, 4), all_distinct(L), L ins 1..4, sum(L, #=, X), label([X]), label(L).
L = [1, 2, 3, 4],
X = 10
正确。
But for example it would be nice to be able have CLPFD be able to reason that in length(L, N - 1), L ins 1..N, all_distinct(L) we can calculate sum(L, #=, X) to have X in N (N - 1) / 2 - N..N (N - 1) / 2 - 1.
证明整数算术的绝对一般定理,而不是约束传播。那会很好,但我认为它不会走那么远。