Prolog:我如何计算谓词的通过次数和失败次数?

时间:2013-03-18 21:05:36

标签: prolog

我想计算一个没有任何参数的谓词的成功和失败次数。为简单起见,我想测试的谓词是test_arith / 0。 test_arith / 0对is / 2进行了3次测试(同样,为了简单起见。我真的想测试我正在编写的更复杂的谓词,但这些细节会分散这个问题。)(PS我看到另一个问题关于计算谓词的数量是真的。我想在一次通过中计算成功和失败。我不想在每个测试用例中多次运行真实谓词,因为其中一些需要很长时间执行.colred / 3和aggregate_all似乎也是一心一意的,只取得成功。)

test_arith(Passes, Failures) :-
    findall(P-F, (test_arith->(P=1,F=0);(P=0,F=1)), Scores),
    summarize_scores(Scores, 0, 0, Passes, Failures).

test_arith :- 5 is 3 +2.  % Test #1: Should pass
test_arith :- 5 is 2 +2.  % Test #2: Should fail
test_arith :- 4 is 2 +2.  % Test #3: Should pass

summarize_scores([], Passes, Failures, Passes, Failures).
summarize_scores([P-F|Scores], Passes_SF, Failures_SF, Passes, Failures) :-
    Next_Passes is P + Passes_SF,
    Next_Failures is F + Failures_SF,
    summarize_scores(Scores, Next_Passes, Next_Failures, Passes, Failures).

当我跑步时

test_arith(P,F).

我得到了

P = 1,
F = 0.

因为test_arith似乎只被调用一次。 我应该

P = 2,
F = 1.

感谢您提供任何帮助。

我试过了:

test_arith(Passes, Failures) :-
    bagof(P-F, A^(test_arith(A)->(P=1,F=0);(P=0,F=1)), Scores),
    summarize_scores(Scores, 0, 0, Passes, Failures).

test_arith(_) :- 5 is 3 +2.
test_arith(_) :- 5 is 2 +2.
test_arith(_) :- 4 is 2 +2.

test_arith2(Passes) :-
    aggregate(count, A^test_arith(A), Passes).

test_arith(P,F)产量:     P = 1,     F = 0。 test_arith2(P)产生“2”。 (这很好,它的工作原理,但只是我正在寻找的1/4。我需要计算失败次数,每个测试运行一次只能运行一次,在这种情况下需要3次调用。)

然后我尝试为每个测试用例添加一个数字:

test_arith(Passes, Failures) :-
    bagof(P-F, A^(test_arith(A)->(P=1,F=0);(P=0,F=1)), Scores),
    summarize_scores(Scores, 0, 0, Passes, Failures).

test_arith(1) :- 5 is 3 +2.
test_arith(2) :- 5 is 2 +2.
test_arith(3) :- 4 is 2 +2.

得到了:

test_arith(P,F).
    P = 1,
    F = 0.

2 个答案:

答案 0 :(得分:0)

看起来你的findall中有一个拼写错误,其中你的暗示的“else”将F绑定到0和1,而不是P绑定到0和F到1.是否直接从你的代码中复制了?

如果是这样,那可能是为什么aggragate方法只接受真理的原因;虚假案件永远不会过去。

已编辑添加:

虽然我认为利用像findall这样的功能是一种很好的做法,但有时候你无法击败一个好的失败循环;内存使用率相当低,我发现性能相似。在Sicstus prolog中,我的方法几乎可以肯定是这样的:

## function is passed in.
## call(Foo) succeeds.
evaluate(Foo) :-
    call(Foo),
    incrementSuccess,
    !.
## call(Foo) fails.
evaluate(Foo) :-
    incrementFailure.

incrementSuccess :-
    success(N),
    N2 is N + 1,
    retract(success(N)),
    assert(success(N2)),
    !.
incrementSuccess :-
    assert success(1).

[very similar for incrementFailure].

## A fail loop that evaluates all possible bindings
tally(Foo, _Success, _Failure) :-
    evaluate(Foo),
    fail.
## The catch case that passes out the final tallies.
tally(_, Success, Failure) :-
    success(Success),
    failure(Failure).

答案 1 :(得分:0)

我认为问题是( - >)/ 2中的'隐含削减'。尝试

test_arith(Passes, Failures) :-
    findall(P-F, (test_arith, P=1,F=0 ; P=0,F=1), Scores),
    summarize_scores(Scores, 0, 0, Passes, Failures).

你会得到

?- test_arith(P,F).
P = 2,
F = 1.

修改

OT,但我喜欢当我可以使逻辑更紧凑时,当然在图书馆的帮助下。这里有一个等价的定义:

test_arith(Passes, Failures) :-
    findall(R, (test_arith, R=1-0 ; R=0-1), Scores),
    aggregate(r(sum(A),sum(B)), member(A-B, Scores), r(Passes, Failures)).

然后,为什么要建立一个立即扫描的列表?

test_arith(Passes, Failures) :-
    aggregate(r(sum(A),sum(B)), (test_arith, A=1,B=0 ; A=0,B=1), r(Passes, Failures)).

编辑上面的代码不正确,无法统计失败。我被这个特定测试用例似乎工作的事实所迷惑。

在@false的帮助下,这里是reify_call / 3,一个可以解决OP问题的构建块(在SWI-Prolog中测试,其中clause / 2可以说是在ISO兼容性方面得到了扩展,给出了@false评论问题):

test_arith(Passes, Failures) :-
    aggregate(r(sum(T),sum(F)), reify_call(test_arith, T, F), r(Passes, Failures)).

:- meta_predicate reify_call(0, -, -).

reify_call(Pred, True, False) :-
    clause(Pred, Cl), (call(Cl) -> True = 1, False = 0 ; True = 0, False = 1).