Path: utzoo!attcan!uunet!mcvax!tuvie!tuhold!thom From: thom@tuhold (Thom Fruehwirth) Newsgroups: comp.lang.prolog Subject: more on permutations Message-ID: <1161@tuhold> Date: 17 Aug 88 11:18:25 GMT Organization: Institut f. Angewandte Informatik, TU Vienna Lines: 78 When commenting on permutations the last time I asked if it is possible to write a permutation predicate using only a single predicate permute/n for its definition. Richard O'Keefe in article <209@quintus.UUCP> did it by a welldone transformation from the initial permute/2 predicate ending up in permute/6. I agree with him that: >I don't think it's particularly useful to have permutation done >with only one recursive predicate, but I think the derivation of >the result may be of interest. Anyway, here is my version: permute(A,B) :- permut permute([],[],[]). permute([X|A],[X|B],C) :- B=[_|_],permute(A,B,C);permute(C,B,A). permute([X|A],B,C) :- permute(A,B,[X|C]). The explicit unification in the second clause of permute/3 avoids duplication of every solution (this happens as both subgoals of the disjunction can match the first, base clause). This can also be avoided by partial evaluation resulting in: perm11([],[]). perm11(A,B) :- perm11(A,B,[]). perm11([X],[X],[]). perm11([X|A],[X|B],C) :- perm11(A,B,C);perm11(C,B,A). perm11([X|A],B,C) :- perm11(A,B,[X|C]). The idea of permute/3 is that the third argument is an intermediate storage for elements of the first argument. So the head X of the first argument is either passed to the resulting second argument directly or to the third argument for later use. The third argument is utilized by simply exchanging it with the first argument (expressed by the disjunction in the second clause). In article <1394@kulcs.kulcs.uucp> bimbart@kulcs.uucp (Bart Demoen) also uses same_length/2 to ensure commutative behaviour of perm/2: > permute_6(X, Y) :- > same_length(X,Y), > permute_2(X,Y) . > > same_length([], []) . > same_length([X|L1],[Y|L2]) :- > same_length(L1,L2) . > > permute_2([], []). > permute_2([X|Xs], Ys1) :- > permu> select(X, Ys1, Ys). and adds: > permute_6 is symmetric, so it is easier to understand that it > can be used in a symmetric way But permute_2 itself isn't symmetric. Here is a full symmetric version of permute_2/2 (unfortunately non-commutative and tail-recursive thus inefficient): permute_2([],[]). permute_2([X|Xs],[X|Ys]):- permute_2(Xs,Ys). permute_2([X|Xs],[Y|Ys select(X,Ys,Ys1), select(Y,Xs,Xs1), permute_2(Xs1,Ys1). Note that the first two clauses are equivalent to same_length/2. I conclude the discussion on permutations has shown two things: -for determinstic predicates use tail recursion, for indeterministic predicates left recursion is more efficient (this was pointed out by Bart Demoen) - it is fun to play around with predic Sometimes its even useful. thom fruehwirth technical university of vienna