I know the original question was posted quite some time ago, but I was very recently working through some of the problems in The Art Of Prolog as well and thought over the even/odd permutation problem for a few days. I didn't want to open a duplicate problem, so I'm posting my solution here.
The problem in the book asks:
Write programs for even_permutation(Xs, Ys)
and odd_permutation(Xs,
Ys)
that find Ys
, the even and odd permutations, respectively,
of a list Xs
. For example, even_permutation([1,2,3], [2,3,1])
and
odd_permutation([1,2,3], [2,1,3])
are true.
So it's asking for permutation generators, not just verifiers. @hardmath has provided a link to the correct definition of even or odd permutation. The authors of the book gave two simple examples to illustrate.
For me, the key was figuring out a recursive definition for an even or odd permutation. For all permutations, the classical permutation generator in Prolog uses the following notion:
- Every permutation of N+1 elements is a list representing a permutation of N of the elements with the (N+1)st element inserted into the list.
The predicate select
or insert
is used to do the insertion.
For even and odd permutations, I considered a similar idea:
Every even permutation of N+1 elements is either a list representing an even permutation of N of the elements with the (N+1)st element inserted at an odd position in the list, or a list representing an odd permutation of N of the elements with the (N+1)st element inserted at an even position in the list.
Every odd permutation of N+1 elements is either a list representing an odd permutation of N of the elements with the (N+1)st element inserted at an odd position in the list, or a list representing an even permutation of N of the elements with the (N+1)st element inserted at an even position in the list.
The rational is that the insertion of an element at an odd position represents an even number of swaps relative to the original list (the front of the list, being the first position, requires no swaps, so it's even). Similarly, the insertion of an element at an even position represents an odd number of swaps relative to the original list.
If I add to this the rule that the empty list is it's own even permutation, then I can define the following predicates as follows to generate the even and odd permutations:
even_permutation( [], [] ).
even_permutation( [X|T], Perm ) :-
even_permutation( T, Perm1 ),
insert_odd( X, Perm1, Perm ).
even_permutation( [X|T], Perm ) :-
odd_permutation( T, Perm1 ),
insert_even( X, Perm1, Perm ).
odd_permutation( [X|T], Perm ) :-
odd_permutation( T, Perm1 ),
insert_odd( X, Perm1, Perm ).
odd_permutation( [X|T], Perm ) :-
even_permutation( T, Perm1 ),
insert_even( X, Perm1, Perm ).
insert_odd( X, InList, [X|InList] ).
insert_odd( X, [Y,Z|InList], [Y,Z|OutList] ) :-
insert_odd( X, InList, OutList ).
insert_even( X, [Y|InList], [Y,X|InList] ).
insert_even( X, [Y,Z|InList], [Y,Z|OutList] ) :-
insert_even( X, InList, OutList ).