序言,测试标签启发式(Prolog, testing labeling heuristics)

2019-10-19 07:45发布

我工作的一些实验中Sicstus Prolog的比较不同的标签启发。

但是,我一直陷入“资源的错误:内存不足”。

我敢肯定,我做错事,我testcode。

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

:- 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释放资源?

另外:这是衡量标签时的正确方法是什么? 没有更好的方法来做到这一点?

Answer 1:

你是不是做什么严格的错,但你尝试运行

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

对于N高达1000000的系统构造与精度N的搜索树,并且具有用于存储变量和每个级别的约束系统的中间状态。 这需要大量的内存对于大N,和你得到一个内存溢出已经与大N. 来看,这是完全可能的

第二个问题是,你在递归循环运行的基准,即要有效地创建一个结合

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

而且由于每次调用ATEST与它的第一个解决方案/ 2成功并围绕保持其搜索状态,这意味着你要创建一个搜索树250500250000个水平...

最简单的改进是切割通过改变您的代码到第一溶液中之后的每个搜索once(atest(C,R)) 。 进一步的改进是在故障驱动的循环中运行的基准

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

这将释放内存更快,更快,并降低测量的失真由于垃圾收集。



Answer 2:

顶层隐藏备用答案

如果您正在测试t1上SICStus'顶层外壳,一些规模较小的值,你可能会得到错误的印象,即t1都有一个确切的答案/解决方案。 然而,这种情况并非如此! 因此,顶层为您隐藏其他的答案。 这是SICStus顶层不显示进一步的答案,如果查询不包含变量的特殊行为。 但有一个总x的! 为您的标签很多解决方案,X! 每个测试用例以及用于其他的解决方案的定时是一些随机值。 您是内存不足,因为每个测试用例,序言保持的纪录继续生产每个测试用例的一个解决方案。

循环

我不推荐使用故障驱动回路测试,而是使用下面的循环,这是非常相似的,但更安全:

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

最大的不同的故障从动环是当atest/2意外失败一些CR 在故障驱动循环,这将基本上去忽视,而上述构建将失败。

有些系统提供了一个谓语forall/2用于这一目的。

定时

如果你做的时间,更好地只使用列表的第一个元素和计算的区别:

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

以这种方式替代答案目标会给你一个更有意义的价值。



文章来源: Prolog, testing labeling heuristics