这是my previous answer 的替代方案。它基于clpfd和meta-predicatemapadj/3:
:- use_module(library(clpfd)).
使用meta-predicatetfilter/3、bool01_t/2和clpfdsum/3我们定义:
z_z_momsign(Z0,Z1,X) :-
X #= max(-1,min(1,Z1-Z0)).
z_z_absmomsign(Z0,Z1,X) :-
X #= min(1,abs(Z1-Z0)).
#\=(X,Y,Truth) :-
X #\= Y #<==> B,
bool01_t(B,Truth).
最后,我们这样定义zs_invcount/2:
zs_invcount(Zs,N) :-
mapadj(z_z_momsign,Zs,Ms0),
tfilter(#\=(0),Ms0,Ms),
mapadj(z_z_absmomsign,Ms,Ds),
sum(Ds,#=,N).
使用示例:
?- zs_invcount([1,2,3],0),
zs_invcount([1,2,3,2],1),
zs_invcount([1,2,3,3,2],1), % works with duplicate items, too
zs_invcount([1,2,3,3,2,1,1,1],1),
zs_invcount([1,2,3,3,2,1,1,1,4,6],2),
zs_invcount([1,2,3,3,2,1,1,1,4,6,9,1],3),
zs_invcount([1,2,3,3,2,1,1,1,4,6,9,1,1],3).
true.
编辑
更详细地考虑执行以下示例查询:
?- zs_invcount([1,2,4,3,2,3,3,4,5,6,7,6,6,6,5,8],N).
让我们一步一步来!
-
对于所有相邻的列表项,计算它们的“动量”符号:
?- Zs = [1,2,4,3,2,3,3,4,5,6,7,6,6,6,5,8], mapadj(z_z_momsign,Zs,Ms0)。
Zs = [1,2, 4,3, 2,3,3,4,5,6,7, 6,6,6, 5,8],
Ms0 = [ 1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1 ]。
-
消除0的所有符号值:
?- Ms0 = [1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1], tfilter(#\=(0),Ms0 ,小姐)。
Ms0 = [1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1],
女士 = [1,1,-1,-1,1, 1,1,1,1,-1, -1,1]。
-
获得“动量反转”,即动量动量的绝对符号。
?- Ms = [1,1,-1,-1,1,1,1,1,1,-1,-1,1],mapadj(z_z_absmomsign,Ms,Ds)。
女士 = [1,1,-1,-1,1,1,1,1,1,-1,-1,1],
Ds = [ 0,1, 0, 1,0,0,0,0,1, 0, 1 ]。
-
最后用sum/3总结“动量反转”的次数:
?- Ds = [0,1,0,1,0,0,0,0,1,0,1], sum(Ds,#=,N)。
N = 4,Ds = [0,1,0,1,0,0,0,0,1,0,1]。
或者,一次完成所有步骤:
:- Zs = [1,2,4, 3, 2,3,3,4,5,6,7, 6,6,6, 5,8], mapadj(z_z_momsign,Zs,Ms0),
Ms0 = [ 1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1 ], tfilter(#\=(0),Ms0,Ms ),
Ms = [ 1,1,-1,-1,1, 1,1,1,1,-1, -1,1 ], mapadj(z_z_absmomsign,Ms,Ds),
Ds = [ 0,1, 0, 1, 0, 0,0,0,1, 0, 1 ], sum(Ds,#=,N),
N = 4。