Search code examples
prolog

Permutation of a list where numbers must change its position in Prolog


I'm trying to solve this question for my assignment.

The predicate acceptable_permutation(L,R) should succeed only if R represents an acceptable permutation of the list L. For example: [2,1,3] is not an acceptable permutation of the list [1,2,3] because 3 did not change its position.

The outputs are supposed to be like this:

?- acceptable_permutation([1,2,3],R).
R = [2,3,1] ;
R = [3,1,2] ;
false

?- acceptable_permutation([1,2,3,4],R).
R = [2,1,4,3] ;
R = [2,3,4,1] ;
R = [2,4,1,3] ;
R = [3,1,4,2] ;
R = [3,4,1,2] ;
R = [3,4,2,1] ;
R = [4,1,2,3] ;
R = [4,3,1,2] ;
R = [4,3,2,1] ;
false.

My outputs of my code however gives:

?- acceptable_permutation([1,2,3],R).
R = [1,2,3] ;
R = [1,3,2] ;
R = [2,1,3] ;
R = [2,3,1] ;
R = [3,1,2] ;
R = [3,2,1] ;

?- acceptable_permutation([1,2,3,4],R).
R = [1,2,3,4] ;
R = [1,2,4,3] ;
R = [1,3,2,4] ;
R = [1,3,4,2] ;
R = [1,4,2,3] ;
R = [1,4,3,2] ;
R = [2,1,3,4] ;
R = [2,1,4,3] ;
R = [2,3,1,4] ;
R = [2,3,4,1] ;
R = [2,4,1,3] ;
R = [2,4,3,1] ;
R = [3,1,2,4] ;
R = [3,1,4,2] ;
R = [3,2,1,4] ;
R = [3,2,4,1] ;
R = [3,4,1,2] ;
R = [3,4,2,1] ;
R = [4,1,2,3] ;
R = [4,1,3,2] ;
R = [4,2,1,3] ;
R = [4,2,3,1] ;
R = [4,3,1,2] ;
R = [4,3,2,1] ;
false.

My code is the following:

acceptable_permutation(list,list).

del(symbol,list,list).

del(X,[X|L1], L1).

del(X,[Y|L1], [Y|L2]):-
    del(X,L1, L2).
    acceptable_permutation([] , []).

acceptable_permutation(L, [X|P]):-
    del(X, L, L1),
    acceptable_permutation(L1, P).

Please tell me where exactly the problem is, so that my outputs should match the correct outputs. I would appreciate a lot if you show me how exactly it is done.


Solution

  • The problem is that you don't check that all the elements of the output list are in a different position than the input list. You should add a predicate to check this, like that:

    perm(L,LO):-
        acceptable_permutation(L,LO),
        different_place(L,LO).
    
    different_place([A|T0],[B|T1]):-
        A \= B,
        different_place(T0,T1).
    different_place([],[]).
    
    ?- perm([1,2,3],R).
    R = [2, 3, 1]
    R = [3, 1, 2]
    false
    

    Improvement 1: instead of creating your own predicate (in this case, different_place/2), you can use maplist/3 with \=/2 in this way:

    perm(L,LO):-
        acceptable_permutation(L,LO),
        maplist(\=,L,LO).
    

    Improvement 2: swi prolog offers the predicate permutation/2 that computes the permutations of a list. So you can solve your problem with only three lines:

    find_perm(L,LO):-
        permutation(L,LO),
        maplist(\=,L,LO).
    
    ?- find_perm([1,2,3],L).
    L = [2, 3, 1]
    L = [3, 1, 2]
    false