Вы можете быстро увидеть проблему при трассировке:
?- trace, pairwise_min( [(25,25),(24,24),(23,23),(22,22),(21,21),(20,20),(19,19),(18,18),(17,17),(16,16),(15,15),(14,14),(13,13),(12,12),(11,11),(10,10),(9,9),(8,8),(7,7),(6,6),(5,5),(4,4),(3,3),(2,2),(1,1)], X ).
Call: (7) pairwise_min([ (25, 25), (24, 24), (23, 23), (22, 22), (21, 21), (20, 20), (19, 19), (..., ...)|...], _G737) ?
... snip ...
Call: (30) pairwise_min([ (2, 2), (1, 1)], (_G1065, _G1066)) ?
Call: (31) pairwise_min([ (1, 1)], (_G1068, _G1069)) ?
Exit: (31) pairwise_min([ (1, 1)], (1, 1)) ?
Call: (31) 1>2 ?
Fail: (31) 1>2 ?
Redo: (30) pairwise_min([ (2, 2), (1, 1)], (_G1065, _G1066)) ?
Call: (31) pairwise_min([ (1, 1)], (_G1065, _G1066)) ?
Exit: (31) pairwise_min([ (1, 1)], (1, 1)) ?
Call: (31) 1=<2 ?
Exit: (31) 1=<2 ?
Exit: (30) pairwise_min([ (2, 2), (1, 1)], (1, 1)) ?
Call: (30) 1>3 ?
Fail: (30) 1>3 ?
Redo: (29) pairwise_min([ (3, 3), (2, 2), (1, 1)], (_G1062, _G1063)) ?
Call: (30) pairwise_min([ (2, 2), (1, 1)], (_G1062, _G1063)) ?
Call: (31) pairwise_min([ (1, 1)], (_G1068, _G1069)) ?
Exit: (31) pairwise_min([ (1, 1)], (1, 1)) ?
Call: (31) 1>2 ?
Fail: (31) 1>2 ?
Redo: (30) pairwise_min([ (2, 2), (1, 1)], (_G1062, _G1063)) ?
Call: (31) pairwise_min([ (1, 1)], (_G1062, _G1063)) ?
Exit: (31) pairwise_min([ (1, 1)], (1, 1)) ?
Call: (31) 1=<2 ?
Exit: (31) 1=<2 ?
По сути, проблема заключается в том, что вы в конечном итоге вызываете pairwise_min(T, ...)
в оба случаях, хотя во втором случае это не будет отличаться. Попарный минимум хвоста — это попарный минимум хвоста, независимо от того, как текущий элемент сверяется с ним.
Хорошим решением было бы исключить второе правило, используя явное условное выражение, что-то вроде этого:
pairwise_min( [X], X ) :- !.
pairwise_min( [(A,B)|T], (RA,RB) ) :-
pairwise_min(T, (A1,B1)), !,
(B1 > B -> (RA = A, RB = B)
; (RA = A1, RB = B1)).
Существенным препятствием для удобочитаемости для меня является то, что я действительно не понимаю, какой порядок вы пытаетесь достичь с помощью своего попарного минимума. Но в будущем было бы неплохо выделить это в отдельный предикат. У меня нет уверенности, что я правильно понял ваш минимум; не правда ли, что @</2
сделает то, что вы хотите? Если это так, вы можете сделать это с очень плотной хвостовой рекурсией:
minimum([X|Xs], Min) :- minimum(Xs, X, Min).
minimum([], Min, Min).
minimum([X|Xs], MinSoFar, Min) :-
(X @< MinSoFar -> minimum(Xs, X, Min)
; minimum(Xs, MinSoFar, Min)).
Если это не так, вы можете написать свой собственный предикат min_pair/2
, который сравнивает две пары, и использовать его вместо @</2
и получить преимущество. Или вызовите его из исправленного pairwise_min/2
выше и убедитесь в преимуществах оптимизации хвостового вызова.
Я думаю, у вас возникнут проблемы с улучшением производительности этой версии.
person
Daniel Lyons
schedule
04.12.2013