How to find the number of inversions in a list in Prolog

前端 未结 3 1197
一整个雨季
一整个雨季 2021-01-22 22:50

As someone who\'s new to Prolog, I\'m looking to find out what a good way to count the number of inversions in a list.

I know how to flatten a matrix using flatten

3条回答
  •  执念已碎
    2021-01-22 23:17

    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!

    1. 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 ].
      
    2. 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].
      
    3. 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 ].
      
    4. 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.
    

提交回复
热议问题