Prolog performance and recursion type

后端 未结 4 921
盖世英雄少女心
盖世英雄少女心 2021-01-04 14:34

I was playing with permutation in a couple of programs and stumbled upon this little experiment:

Permutation method 1:

permute([], []).
         


        
4条回答
  •  萌比男神i
    2021-01-04 14:59

    Nice example. But I would rather use, it doesn't leave a choice point in permute([], []):

    permute3([], []). 
    permute3([H|T], [P|P1]) :- 
        select(P, [H|T], L1), 
        permute3(L1, P1). 
    

    Its tail recursive and like 20% faster than permute2/2, but still not as fast as permute1/2.

    ?- time((permute2([1,2,3,4,5,6,7,8,9,0],_), fail; true)).
    % 29,592,302 inferences, 1.653 CPU in 1.667 seconds (99% CPU, 17896885 Lips)
    true.
    
    ?- time((permute3([1,2,3,4,5,6,7,8,9,0],_), fail; true)).
    % 25,963,501 inferences, 1.470 CPU in 1.480 seconds (99% CPU, 17662390 Lips)
    true.
    

    But I am not sure whether the explanation by mat is correct. It could be also the case that permute1/2 does less often perform LCO than permute3/2 does.

    Namely of n! results of the sub call permute1/2, only the last redo doesn't leave a choice point. On the other hand in permute3/2 every select/3 call has n results and doesn't

    leave a choice point in the last redo. I did a little test, write a period for each LCO:

    ?- permute1([1,2,3],_), fail; nl.
    ...
    ?- permute3([1,2,3],_), fail; nl.
    ..........
    

    LCO has not an extreme benefit in a fail loop. But the Prolog system doesn't know about it. So I guess thats where unnecessary time is spent, to a larger amount in permute3/2.

提交回复
热议问题