我想计算一个没有任何参数的谓词的成功和失败次数。为简单起见,我想测试的谓词是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.
答案 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).