我尝试将 Picat 样式自动转换为一些更高阶的循环结构。然后是高阶循环结构的手动内联。自动 Picat 风格翻译的输入是:
:- table p/2.
p(0)=1 => !.
p(N)=Z =>
Z=0, K=1,
M is K*(3*K-1)//2,
while(M=<N,
(Z:=Z-(-1)^K*p(N-M),
K:=K+1,
M:=K*(3*K-1)//2)),
K:=1,
M:=K*(3*K+1)//2,
while(M=<N,
(Z:=Z-(-1)^K*p(N-M),
K:=K+1,
M:=K*(3*K+1)//2)).
在此答案的末尾可以找到指向翻译器代码的链接。自动翻译器给了我:
?- listing(p_a/2).
% example2.pl
:- sys_notrace p_a/2.
p_a(0, 1) :-
!.
p_a(N, A) :-
Z = 0,
K = 1,
M is K*(3*K-1)//2,
while([B, C, D, E]\[F, C, G, H]\(G is D- -1^E*p(C-B),
H is E+1,
F is H*(3*H-1)//2), [I, J, _, _]\(I =< J), [M, N, Z,
K], [_, N, L, _]),
O is 1,
P is O*(3*O+1)//2,
while([Q, R, S, T]\[U, R, V, W]\(V is S- -1^T*p(R-Q),
W is T+1,
U is W*(3*W+1)//2), [X, Y, _, _]\(X =< Y), [P, N, L,
O], [_, N, A, _]).
它使用算术函数评估 p(CB) 和 p(RQ)。在我的 Prolog 系统算术函数评估使用本机 Java 堆栈,我无法评估 6666:
% ?- p(100,X).
% X = 190569292
% ?- p(6666,X).
% java.lang.StackOverflowError
% at jekpro.reference.arithmetic.EvaluableElem.moniEvaluate(EvaluableElem.java:207)
此外,使用 while/4 元谓词有点慢。所以我修改了代码,消除了算术函数评估并内联了 while/4。我还使用了一个可怜的 mans 表,它更快一点:
:- thread_local p_cache/2.
p_manual(N, X) :- p_cache(N, X), !.
p_manual(0, 1) :-
!, assertz(p_cache(0, 1)).
p_manual(N, A) :-
Z = 0,
K = 1,
M is K*(3*K-1)//2,
p21([M, N, Z, K], [_, N, L, _]),
O is 1,
P is O*(3*O+1)//2,
p22([P, N, L, O], [_, N, A, _]),
assertz(p_cache(N, A)).
p21([B, C, D, E], O1) :- B =< C, !,
L is C-B,
p_manual(L, M),
G is D- -1^E*M,
H is E+1,
F is H*(3*H-1)//2,
p21([F, C, G, H], O1).
p21(I1, I1).
p22([Q, R, S, T], O2) :- Q =< R, !,
L is R-Q,
p_manual(L, M),
V is S- -1^T*M,
W is T+1,
U is W*(3*W+1)//2,
p22([U, R, V, W], O2).
p22(I2, I2).
现在事情开始看起来不错。2.743 秒下降到:
/* SWI-Prolog 8.3.21 */
?- time(p_manual(6666,X)).
% 4,155,198 inferences, 0.879 CPU in 0.896 seconds (98% CPU, 4729254 Lips)
X = 193655306161707661080005073394486091998480950338405932486880600467114423441282418165863.
/* Jekejeke Prolog 1.5.0 */
?- time(p_manual(6666,X)).
% Up 736 ms, GC 20 ms, Threads 714 ms (Current 04/14/21 02:16:45)
X = 193655306161707661080005073394486091998480950338405932486880600467114423441282418165863
开源:
Picat 风格脚本翻译器 II
https://gist.github.com/jburse/8a24fe5668960c8889770f40c65cdf35#file-picat2-pl
Picat 样式脚本示例 II
https://gist.github.com/jburse/8a24fe5668960c8889770f40c65cdf35#file-example2-pl
Picat 样式脚本内联
https://gist.github.com/jburse/8a24fe5668960c8889770f40c65cdf35#file-tune-pl