Loops Picat中的配分函数P
我得到了配分函数pLoops Picat中的配分函数P,loops,prolog,picat,Loops,Prolog,Picat,我得到了配分函数p的以下实现 在序言中,取自罗塞塔: 如何在Picat中实现同样的功能?是不是 确实,aggregate_all+sum可以替换为foreach+:=? 那么Picat中的bignums呢?bignums在Picat中没有问题。 以下是我的Picat版本(受枫树方法启发): 我的Picat版本大约需要0.2秒 Picat> time(println('p(6666)'=partition1(6666))) p(6666) = 19365530616170766108000
的以下实现 在序言中,取自罗塞塔: 如何在Picat中实现同样的功能?是不是
确实,aggregate_all+sum可以替换为foreach+:=?
那么Picat中的bignums呢?bignums在Picat中没有问题。 以下是我的Picat版本(受枫树方法启发): 我的Picat版本大约需要0.2秒
Picat> time(println('p(6666)'=partition1(6666)))
p(6666) = 193655306161707661080005073394486091998480950338405932486880600467114423441282418165863
CPU time 0.206 seconds.
更新
这里有一个版本在Picat中使用findall
,有点模仿您的方法:
table
partition1(0) = 1.
partition1(N) = P =>
S = 0,
K = 1,
M = (K*(3*K-1)) // 2,
while (M <= N)
M := (K*(3*K-1)) // 2,
S := S - ((-1)**K)*partition1(N-M),
K := K + 1
end,
K := 1,
M := (K*(3*K+1)) // 2,
while (M <= N)
M := (K*(3*K+1)) // 2,
S := S - ((-1)**K)*partition1(N-M),
K := K + 1
end,
P = S.
table
p(0, 1) :- !.
p(N, X) :-
A = sum(findall(Z, (between(1,N,K), M is K*(3*K-1)//2,
(M>N, !, fail; p(N-M,Y), Z is (-1)**K*Y)))),
B = sum(findall(Z, (between(1,N,K), M is K*(3*K+1)//2,
(M>N, !, fail; p(N-M,Y), Z is (-1)**K*Y)))),
X is -A-B.
但速度要慢得多(2.6秒vs 0.2秒):
我还测试了如何实现相同的方法,即在SWI Prolog中使用findall/3
:
:- table p2/2.
p2(0, 1) :- !.
p2(N, X) :-
findall(Z, (between(1,N,K), M is K*(3*K-1)//2,
(M>N, !, fail; L is N-M, p2(L,Y), Z is (-1)**K*Y)), AA),
sum(AA,A),
findall(Z, (between(1,N,K), M is K*(3*K+1)//2,
(M>N, !, fail; L is N-M, p2(L,Y), Z is (-1)**K*Y)), BB),
sum(BB,B),
X is - A - B.
sum(L,Sum) :-
sum(L,0,Sum).
sum([],Sum,Sum).
sum([H|T],Sum0,Sum) :-
Sum1 is Sum0 + H,
sum(T,Sum1,Sum).
它比Picat的findall
方法快,与您的版本差不多(稍微快一点,但推断更多)
我尝试了一个自动的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)).
另外,while/4元谓词的使用有点慢。因此,我对代码进行了修改,消除了算术函数求值和内联while/4。我还使用了一个穷人的表格,速度稍微快一点:
:- 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).
开源:
Picat风格脚本翻译程序IIPicat风格脚本示例II
Picat风格的脚本内联
是的,while比foreach循环更适合此算法。我会看看是否可以用foreach/1或列表理解来镜像您的算法,您是指在while条件下重新分配(即
while(M:=…将您的解决方案添加到rosetta中,希望您对此满意:太好了。谢谢!
:- table p2/2.
p2(0, 1) :- !.
p2(N, X) :-
findall(Z, (between(1,N,K), M is K*(3*K-1)//2,
(M>N, !, fail; L is N-M, p2(L,Y), Z is (-1)**K*Y)), AA),
sum(AA,A),
findall(Z, (between(1,N,K), M is K*(3*K+1)//2,
(M>N, !, fail; L is N-M, p2(L,Y), Z is (-1)**K*Y)), BB),
sum(BB,B),
X is - A - B.
sum(L,Sum) :-
sum(L,0,Sum).
sum([],Sum,Sum).
sum([H|T],Sum0,Sum) :-
Sum1 is Sum0 + H,
sum(T,Sum1,Sum).
?- time(p2(6666,X)).
% 14,636,851 inferences, 1.814 CPU in 1.814 seconds (100% CPU, 8070412 Lips)
X = 193655306161707661080005073394486091998480950338405932486880600467114423441282418165863.
:- 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(100,X).
% X = 190569292
% ?- p(6666,X).
% java.lang.StackOverflowError
% at jekpro.reference.arithmetic.EvaluableElem.moniEvaluate(EvaluableElem.java:207)
:- 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).
/* 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