【问题标题】:Prolog, testing labeling heuristicsProlog,测试标签启发式
【发布时间】:2014-03-08 07:57:31
【问题描述】:

我正在做一些实验来比较 Sicstus Prolog 中不同的标签启发式方法。

但我不断遇到“资源错误:内存不足”。

我很确定我在测试代码中做错了什么。

以下代码将复制我的问题:

:- use_module(library(clpfd)).
:- use_module(library(lists)).

atest( R, C ):-
    X is R * C,
    length( M, X),
    domain( M, 0, X),
    all_distinct( M ),

    statistics(walltime, [_,_SinceLast]),
    labeling( [],M ),
    statistics(walltime, [_,SinceLast]),

    write('Labeling time: '), write(SinceLast),write('ms'),nl.


% Testcode for looping through alot of variations and run one test for each variant
t1:-
    Cm = 1000,
    Cr = 1000,
    (
    for(C,0, Cm),
    param([Cm,Cr])
    do
        (
        for(R, 0, Cr ),
        param([C])
        do
            atest( C, R )
        )
    ).      

调用 t1 谓词后不久,我收到“资源错误:内存不足”异常。

我想我应该在调用 atest 释放资源后做点什么?

另外:这是衡量标记时间的正确方法吗?有更好的方法吗?

【问题讨论】:

  • 您要测量什么?是找到第一个解决方案的时间,还是标记所有解决方案的时间?目前你既不做也不做。

标签: prolog clpfd sicstus-prolog


【解决方案1】:

您并没有做任何严重错误,但您正在尝试运行

length(Xs,N), domain(Xs,0,N), all_distinct(Xs), labeling([],Xs).

N 最大为 1000000。系统构建深度为 N 的搜索树,并且必须存储变量的中间状态和每个级别的约束系统。对于大 N,这会占用大量内存,并且很有可能您已经在使用大 N 的 single 运行时遇到了内存溢出。

第二个问题是您在递归循环中运行基准测试,即您正在有效地创建一个连接

atest(0,0), ..., atest(1000,1000)

并且由于每次调用 attest/2 都会成功使用其第一个解决方案并保持其搜索状态,这意味着您正在尝试创建具有 250500250000 个级别的搜索树...

最简单的改进是在第一个解决方案之后通过将代码更改为once(atest(C,R)) 来减少每次搜索。进一步的改进是在 失败驱动的循环中运行基准测试

(
    between(0,Cm,C),
    between(0,Cr,R), 
    once(atest(C,R)),
    fail
;
    true
)

这将更快更快地释放内存,并减少由于垃圾收集而导致的测量失真。

【讨论】:

  • Tnx。这解决了我的问题。我还在 fail/0 之前 trimcore/0,这看起来有助于进一步回收使用的内存。
【解决方案2】:

顶层隐藏替代答案

如果您在 SICStus 的顶级 shell 上使用一些较小的值测试 t1,您可能会产生错误的印象,即 t1 只有一个答案/解决方案。然而,这种情况并非如此!所以顶层对你隐藏了其他答案。这是 SICStus 顶层中的一种特殊行为,如果查询不包含变量,则不会显示进一步的答案。但是一共有x!许多标签解决方案,x! 对于每个测试用例和其他解决方案的时间是一些随机值。您的内存不足是因为对于每个测试用例,Prolog 都会保留记录以继续为每个测试用例生成下一个解决方案。

循环

我不建议使用故障驱动循环进行测试,而是使用以下非常相似但更安全的循环:

\+ (
      between(0, Cm, C),
      between(0, Cr, R),
      \+ atest(C, R)
   ).

与失败驱动循环的最大区别是当atest/2 意外失败某些CR。在失败驱动的循环中,这基本上不会被注意到,而上面的构造会失败。

一些系统为此提供了谓词forall/2

时间

如果你做计时,最好只使用列表的 first 元素并计算差异:

statistics(walltime, [T0|_]),
Goal,
statistics(walltime, [T1|_]),
D is T1 - T0.

通过这种方式,目标的替代答案将为您提供更有意义的价值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 2013-07-11
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多