【问题标题】:SWI-Prolog stack limit exceeded with tiny problem space using clpfd使用 clpfd 的问题空间很小,超出了 SWI-Prolog 堆栈限制
【发布时间】:2019-12-11 16:23:24
【问题描述】:

我尝试为这种行为展示一个最小的示例。这是我加载的代码:

:- use_module(library(clpfd)).

gcd(A, 0, A) :- !.
gcd(0, B, B) :- !.
gcd(A, B, C) :- A #> B, !, A1 #= A mod B, gcd(A1, B, C).
gcd(A, B, C) :- A #=< B, A1 #= B mod A, gcd(A1, A, C).

ncalc(N, X, Y) :-
    Y #=< N,
    X*X #= (Y),
    X #< Y,
    X #> 0,
    gcd(X, Y, 1).

查询ncalc(9, X, Y).我得到:

ERROR: Stack limit (1.0Gb) exceeded
ERROR:   Stack sizes: local: 1Kb, global: 0.7Gb, trail: 9Kb
ERROR:   Stack depth: 1,548,057, last-call: 100%, Choice points: 5
ERROR:   In:
ERROR:     [1,548,057] clpfd:pop_queue(_176712142, <compound fast_slow/2>, 1)
ERROR:     [1,548,056] clpfd:pop_queue(_176712170)
ERROR:     [1,548,055] clpfd:fetch_propagator(_176712188)
ERROR:     [1,548,054] clpfd:do_queue
ERROR:     [1,548,052] clpfd:parse_clpfd('<garbage_collected>', _176712222)
ERROR:
ERROR: Use the --stack_limit=size[KMG] command line option or
ERROR: ?- set_prolog_flag(stack_limit, 2_147_483_648). to double the limit.

查询ncalc(8, X, Y). 立即返回false.。也可以查询ncalc(9, 1, Y).ncalc(9, 8, Y).(X 的所有可能有效范围)。为什么它只适用于更简单的情况?有解决方法吗?谢谢!

PS:我是 prolog 新手,我打算做的事情更复杂,但知道解决方法我可能会调整解决方案。

【问题讨论】:

  • 您应该绝对在使用 clp(fd) 时避免剪切。试着从 state 变化的角度来思考。请注意,此评论很可能无法帮助您解决当前的问题...

标签: prolog swi-prolog clpfd


【解决方案1】:

(让我们忽略编程风格,请参阅@Capelli 的评论。)

未终止的实际原因是 SWI 的 CLP(FD) 系统存在缺陷。这是真正的罪魁祸首:

?- X in 2..3, Y in 4..9, Y mod X#=X1.
X in 2..3,
Y mod X#=X1,
Y in 4..9.

因此系统无法推断出X1 的任何有用信息。将此与 SICStus 进行对比:

| ?- X in 2..3, Y in 4..9, Y mod X#=X1.
Y mod X#=X1,
X in 2..3,
Y in 4..9,
X1 in 0..2 

这里 SICStus 推断 X1 必须在 0..2 之内,因此不是负数。这反过来又避免了下一个推理中的循环问题。

你可以通过坚持非负数来帮助系统,因此模块总是小于操作数。

A1 #&gt;= 0, A1 #=&lt; B, A1 #=&lt; A

同时修复在CLP(Z)

【讨论】:

  • 不错的收获!图书馆(clpfd)需要这么多的manteiner。前段时间我发现了一个测试用例,其中 all_distinct 的性能比 all_diff 差 15 倍......
  • @CapelliC 奇怪的是,两件看似无关的事情在时间上却大体一致。 SWI-Prolog 是 MIT 而不是 LGPL,这在某种程度上是一个大问题。同时,库的新工作只发生在商业的、封闭源代码的 Prolog 实现中(商业用户的源代码许可价格“根据要求报价”)。
  • @User9213:抱歉,我不太理解您的评论 - 您指的是库(clpfd)或许可中的问题吗? AFAIK SWI-Prolog 许可目前是 BSD。 library(clpfd) 和其他人的作者 Markus Triska 选择了 SIRSTUS,因为属性化 vars 接口更适合他所追求的增强功能。
  • @CapelliC 是的,你是对的; 2-clause BSD 类似于 MIT 许可证,我很困惑。我明白这两件事没有关系,这就是我觉得奇怪的原因。不要试图理解很好,因为这只是一句随手的话(我猜也不要喂巨魔)。
猜你喜欢
  • 2016-01-16
  • 2016-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多