Here's an alternative to my previous answer. It is based on clpfd and meta-predicate mapadj/3
:
:- use_module(library(clpfd)).
Using meta-predicate tfilter/3
, bool01_t/2
, and clpfd sum/3
we define:
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).
Finally, we define zs_invcount/2
like so:
zs_invcount(Zs,N) :-
mapadj(z_z_momsign,Zs,Ms0),
tfilter(#\=(0),Ms0,Ms),
mapadj(z_z_absmomsign,Ms,Ds),
sum(Ds,#=,N).
Sample use:
?- 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.
Edit
Consider the execution of following sample query in more detail:
?- zs_invcount([1,2,4,3,2,3,3,4,5,6,7,6,6,6,5,8],N).
Let's proceed step-by-step!
For all adjacent list items, calculate the sign of their "momentum":
?- 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 ].
Eliminate all sign values of 0
:
?- Ms0 = [1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1], tfilter(#\=(0),Ms0,Ms).
Ms0 = [1,1,-1,-1,1,0,1,1,1,1,-1,0,0,-1,1],
Ms = [1,1,-1,-1,1, 1,1,1,1,-1, -1,1].
Get the "momentum inversions", i.e., absolute signs of the momentum of momentums.
?- Ms = [1,1,-1,-1,1,1,1,1,1,-1,-1,1], mapadj(z_z_absmomsign,Ms,Ds).
Ms = [1,1,-1,-1,1,1,1,1,1,-1,-1,1],
Ds = [ 0,1, 0, 1,0,0,0,0,1, 0, 1 ].
Finally, sum up the number of "momentum inversions" using 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].
Or, alternatively, all steps at once:
:- 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.