Ordering lists with constraint logic programming

前端 未结 3 1077
南旧
南旧 2020-12-06 12:01

I was wondering if anyone could help me with this problem: I have to order a list using Prolog with Constraing Logic Programming and I must do it with the more efficient way

3条回答
  •  无人及你
    2020-12-06 12:06

    Here are two implementations using clpfd. Both are similar to the "permutation sort" variants presented in earlier answers. However, both express "permutation" not by using permutation/2, but by a combination of element/3 and all_distinct/1.

    element/3 states that the elements of the sorted list are all members of the original list. all_distinct/1 ensures that the element indices are all different from each other.

    :- use_module(library(clpfd)).
    
    elements_index_item(Vs,N,V) :-
        element(N,Vs,V).
    
    list_sortedA(Xs,Zs) :-
        same_length(Xs,Zs),
        chain(Zs,#=<),
        maplist(elements_index_item(Xs),Ns,Zs),
        all_distinct(Ns),
        labeling([],Ns).
    

    Sample query:

    ?- list_sorted1([9,7,8,5,6,3,4,1,2],Xs).
    Xs = [1, 2, 3, 4, 5, 6, 7, 8, 9] ;
    false.
    

    What if the second argument is known and the first is unknown?

    ?- list_sorted1(Xs,[1,2,3]).
    Xs = [1, 2, 3] ;
    Xs = [1, 3, 2] ;
    Xs = [2, 1, 3] ;
    Xs = [3, 1, 2] ;
    Xs = [2, 3, 1] ;
    Xs = [3, 2, 1].
    

    So far, so good. What if the list to be sorted contains duplicates?

    ?- list_sorted1([5,4,4,3,3,2,2,1],Xs).
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    Xs = [1, 2, 2, 3, 3, 4, 4, 5].
    

    Now that's a lot of redundant answers! Can we do better?


    Eliminating redundant answers

    Yes! The redundant answers in the above query can be eliminated by adding a constraint relating neighboring items in the sorted list and their respective positions in the original list.

    The constraint Z1 #= Z2 #==> N1 #< N2 states: "If two neighboring items in the sorted list are equal then their positions in the original list must be ordered."

    originalPosition_sorted([],[]).
    originalPosition_sorted([_],[_]).
    originalPosition_sorted([N1,N2|Ns],[Z1,Z2|Zs]) :-
        Z1 #= Z2 #==> N1 #< N2,
        originalPosition_sorted([N2|Ns],[Z2|Zs]).
    
    list_sorted2(Xs,Zs) :-
        same_length(Xs,Zs),
        chain(Zs,#=<),
        maplist(elements_index_item(Xs),Ns,Zs),
        originalPosition_sorted(Ns,Zs),
        all_distinct(Ns),
        labeling([],Ns).
    

    But... does it work?

    ?- list_sorted2([5,4,4,3,3,2,2,1],Xs).
    Xs = [1, 2, 2, 3, 3, 4, 4, 5] ;
    false.
    

提交回复
热议问题