Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List DCG与Prolog中的列表求逆_List_Prolog_Clpfd - Fatal编程技术网

List DCG与Prolog中的列表求逆

List DCG与Prolog中的列表求逆,list,prolog,clpfd,List,Prolog,Clpfd,我想数一数列表中的倒数。谓词倒装(+L,-N)将N与该列表中的倒装数统一起来。反转定义为X>Y,并且X出现在列表中Y之前(除非X或Y为0)。例如: ?- inversions([1,2,3,4,0,5,6,7,8],N). N = 0. ?- inversions([1,2,3,0,4,6,8,5,7],N). N = 3. 对于我使用它的目的,列表总是有9个元素,并且总是唯一地包含数字0-8 我对Prolog还很陌生,我正努力做到尽可能简洁和优雅;看来这可能会有很大帮助。我阅读了官方定义和

我想数一数列表中的倒数。谓词
倒装(+L,-N)
N
与该列表中的倒装数统一起来。反转定义为
X>Y
,并且
X
出现在列表中
Y
之前(除非
X
Y
0
)。例如:

?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.

?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
对于我使用它的目的,列表总是有9个元素,并且总是唯一地包含数字
0-8


我对Prolog还很陌生,我正努力做到尽可能简洁和优雅;看来这可能会有很大帮助。我阅读了官方定义和一些教程网站,但仍然不明白它是什么。如有任何帮助,我们将不胜感激。

在SWI Prolog中,使用库和:


我不确定DCG在这里是否有用。虽然我们正在处理一个序列,但在查看每个元素时,在每个点上都会对整个列表进行大量检查

这里有一个CLPFD方法,它实现了反演的“朴素”算法,因此它是透明和简单的,但没有它可能的那么有效(它是O(n^2))。有一个更有效的算法(O(n logn))涉及一种方法,我将在下面进一步展示

:- use_module(library(clpfd)).

inversions(L, C) :-
    L ins 0..9,
    all_distinct(L),
    count_inv(L, C).

% Count inversions    
count_inv([], 0).
count_inv([X|T], C) :-
    count_inv(X, T, C1),     % Count inversions for current element
    C #= C1 + C2,            % Add inversion count for the rest of the list
    count_inv(T, C2).        % Count inversions for the rest of the list

count_inv(_, [], 0).
count_inv(X, [Y|T], C) :-
    (   X #> Y, X #> 0, Y #> 0
    ->  C #= C1 + 1,         % Valid inversion, count it
        count_inv(X, T, C1)
    ;   count_inv(X, T, C)
    ).

?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0 ;
false.

?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.

?-  inversions([0,2,X],1).
X = 1 ;
false.
正如你所见,它确实留下了一个选择点,我还没有理清。
下面是O(n logn)解决方案,它使用排序/合并算法

inversion([], [], 0).
inversion([X], [X], 0).
inversion([HU1, HU2|U], [HS1, HS2|S], C) :- % Ensure list args have at least 2 elements
    split([HU1, HU2|U], L, R),
    inversion(L, SL, C1),
    inversion(R, SR, C2),
    merge(SL, SR, [HS1, HS2|S], C3),
    C #= C1 + C2 + C3.

% Split list into left and right halves
split(List, Left, Right) :-
    split(List, List, Left, Right).
split(Es, [], [], Es).
split(Es, [_], [], Es).
split([E|Es], [_,_|T], [E|Ls], Right) :-
    split(Es, T, Ls, Right).

% merge( LS, RS, M )
merge([], RS, RS, 0).
merge(LS, [], LS, 0).
merge([L|LS], [R|RS], [L|T], C) :-
    L #=< R,
    merge(LS, [R|RS], T, C).
merge([L|LS], [R|RS], [R|T], C) :-
    L #> R, R #> 0 #<==> D, C #= C1+D,
    merge([L|LS], RS, T, C1).
inversion([]、[]、0)。
反转([X],[X],0)。
反转([HU1,HU2 | U],[HS1,HS2 | S],C):-%确保列表参数至少有2个元素
分裂([HU1,HU2 | U],L,R),
反转(L,SL,C1),
反转(R,SR,C2),
合并(SL、SR、[HS1、HS2|S]、C3),
C#=C1+C2+C3。
%将列表分成左右两半
拆分(列表,左,右):-
拆分(列表、列表、左、右)。
拆分(Es、[]、[]、Es)。
拆分(Es,[[u],],Es)。
拆分([E|Es]、[E|T]、[E|Ls],右):-
拆分(Es、T、Ls、右侧)。
%合并(LS、RS、M)
合并([],RS,RS,0)。
合并(LS,[],LS,0)。
合并([L|LS]、[R|RS]、[L|T]、C):-
L#=R,R#>0#D,C#=C1+D,
合并([L | LS],RS,T,C1)。

您可以忽略第二个参数,它是排序列表(如果您只想得到反转计数,那么这只是一个副作用)。

使用clpfd et automaton/8我们可以编写

:- use_module(library(clpfd)).

inversions(Vs, N) :-
             Vs ins 0..sup,
             variables_signature(Vs, Sigs),
             automaton(Sigs, _, Sigs,
                       [source(s),sink(i),sink(s)],
                       [arc(s,0,s), arc(s,1,s,[C+1]), arc(s,1,i,[C+1]),
                        arc(i,0,i)],
                       [C], [0], [N]),
            labeling([ff],Vs).

variables_signature([], []).

variables_signature([V|Vs], Sigs) :-
            variables_signature_(Vs, V, Sigs1),
            variables_signature(Vs, Sigs2),
            append(Sigs1, Sigs2, Sigs).

variables_signature_([], _, []).

variables_signature_([0|Vs], Prev, Sigs) :-
      variables_signature_(Vs,Prev,Sigs).

variables_signature_([V|Vs], Prev, [S|Sigs]) :-
      V #\= 0,
      % Prev #=< V #<==> S #= 0,
      % modified after **false** remark 
      Prev #> V #<==> S,
      variables_signature_(Vs,Prev,Sigs).

此类特定于应用程序的约束通常可以使用具体化的约束(其真值反映为0/1变量的约束)构建。这导致了一个相对自然的公式,其中B是1,前提是要计算的条件满足:

:- lib(ic).

inversions(Xs, N) :-
    ( fromto(Xs, [X|Ys], Ys, [_]), foreach(NX,NXs) do
        ( foreach(Y,Ys), param(X), foreach(B,Bs) do
            B #= (X#\=0 and Y#\=0 and X#>Y)
        ),
        NX #= sum(Bs)       % number of Ys that are smaller than X
    ),
    N #= sum(NXs).

此代码适用于。

这里有另一个解决方案,它不会使用
来保留选择点,如果\u3

inversions([],0).
inversions([H|T], N):-
   if_( H = 0, 
        inversions(T,N),
        ( find_inv(T,H,N1),inversions(T, N2), N #= N1+N2 )
      ).

find_inv([],_,0).
find_inv([H1|T],H,N1):-
   if_( H1=0,
        find_inv(T,H,N1),
        if_( H#>H1, 
             (find_inv(T,H,N2),N1 #= N2+1),
             find_inv(T,H,N1) 
           )
       ).

#>(X, Y, T) :-
   (  integer(X),
      integer(Y)
   -> ( X > Y
      -> T = true
      ;  T = false
      )
   ;  X #> Y,
      T = true
   ;  X #=< Y,
      T = false
   ).
反转([],0)。
反转([H | T],N):-
如果_uh=0,
反转(T,N),
(求逆(T,H,N1),逆(T,N2),N#=N1+N2)
).
查找\u inv([],\u0)。
查找_inv([H1 | T],H,N1):-
如果_u1(H1=0,
查找_inv(T,H,N1),
如果uh#>H1,
(求逆(T,H,N2),N1#=N2+1),
查找库存(T、H、N1)
)
).
#>(X,Y,T):-
(整数(X),
整数(Y)
->(X>Y)
->T=真
;T=假
)
;X#>Y,
T=真
;X#=
这里是定义关系的另一种可能性。首先,
#…和
X
出现在列表中的
Y
之前。。。这是紧接着,还是在之后的任何时候?这确实是一个很好的clpfd示例。我会悬赏一个clpfd-solution@lurker,在
反演([0,2,1],1]之前的任何点。
成功推广
反演([0,2,X],1)。
失败。为什么不修复程序?用
=\=
替换
\=
或将
X>Y
放在第一位是如此简单@谢谢,我会的。。。我曾短暂尝试过使用clpfd:element/3,但它不起作用。聚合和clpfd不会聚集在一起:
反转([0,1,2],N)。
现在失败了??另外,请使用单独的解决方案使用单独的答案。
反转(Xs,1)。
失败,但
Xs=[2,1,0],反转(Xs,1)。
使用6.2开发成功21。有更好的版本吗?看起来像许多开放式CP。还有
((L#>0,R#>0)->
…看起来非常可疑!@false确实,它显示了CPs。这是一种幼稚的方法。我确实更新了
->
表达式,因为它有点过度。@false-good建议。我不太熟悉
/2
操作符。@false:tu es français?Rendons gr–ceáAlain Colmerauer!C'est seulment main que j'ai注意!哎哟!我真是太棒了,我的朋友们:我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们,我的朋友们。
:- use_module(library(clpfd)).

inversions(Vs, N) :-
             Vs ins 0..sup,
             variables_signature(Vs, Sigs),
             automaton(Sigs, _, Sigs,
                       [source(s),sink(i),sink(s)],
                       [arc(s,0,s), arc(s,1,s,[C+1]), arc(s,1,i,[C+1]),
                        arc(i,0,i)],
                       [C], [0], [N]),
            labeling([ff],Vs).

variables_signature([], []).

variables_signature([V|Vs], Sigs) :-
            variables_signature_(Vs, V, Sigs1),
            variables_signature(Vs, Sigs2),
            append(Sigs1, Sigs2, Sigs).

variables_signature_([], _, []).

variables_signature_([0|Vs], Prev, Sigs) :-
      variables_signature_(Vs,Prev,Sigs).

variables_signature_([V|Vs], Prev, [S|Sigs]) :-
      V #\= 0,
      % Prev #=< V #<==> S #= 0,
      % modified after **false** remark 
      Prev #> V #<==> S,
      variables_signature_(Vs,Prev,Sigs).
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.

?- inversions([1,2,3,0,4,5,6,7,8],N).
N = 0 ;
false.

?- inversions([0,2,X],1).
X = 1.
:- lib(ic).

inversions(Xs, N) :-
    ( fromto(Xs, [X|Ys], Ys, [_]), foreach(NX,NXs) do
        ( foreach(Y,Ys), param(X), foreach(B,Bs) do
            B #= (X#\=0 and Y#\=0 and X#>Y)
        ),
        NX #= sum(Bs)       % number of Ys that are smaller than X
    ),
    N #= sum(NXs).
inversions([],0).
inversions([H|T], N):-
   if_( H = 0, 
        inversions(T,N),
        ( find_inv(T,H,N1),inversions(T, N2), N #= N1+N2 )
      ).

find_inv([],_,0).
find_inv([H1|T],H,N1):-
   if_( H1=0,
        find_inv(T,H,N1),
        if_( H#>H1, 
             (find_inv(T,H,N2),N1 #= N2+1),
             find_inv(T,H,N1) 
           )
       ).

#>(X, Y, T) :-
   (  integer(X),
      integer(Y)
   -> ( X > Y
      -> T = true
      ;  T = false
      )
   ;  X #> Y,
      T = true
   ;  X #=< Y,
      T = false
   ).
:- use_module(library(clpfd)).

bool_t(1,true).
bool_t(0,false).

#<(X,Y,Truth)  :- X #< Y #<==> B, bool_t(B,Truth).
#\=(X,Y,Truth)  :- X #\= Y #<==> B, bool_t(B,Truth).
inv_t(X,Y,T) :-
   if_(((Y#<X,Y#\=0),X#\=0),T=true,T=false).
list_inversions(L,I) :-
   list_inversions_(L,I,0).

list_inversions_([],I,I).
list_inversions_([X|Xs],I,Acc0) :-
   list_x_invs_(Xs,X,I0,0),
   Acc1 #= Acc0+I0,
   list_inversions_(Xs,I,Acc1).

list_x_invs_([],_X,I,I).
list_x_invs_([Y|Ys],X,I,Acc0) :-
   if_(inv_t(X,Y),Acc1#=Acc0+1,Acc1#=Acc0),
   list_x_invs_(Ys,X,I,Acc1).
?- list_inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.

?- list_inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.