🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #3527

Re: permutation - versions and their efficiency

#3527
From: Richard A. O'Keefe
Date: Fri, 29 Jul 1988 22:43
106 lines
3510 bytes
In article <1074@tuhold> thom@tuhold (Thom Fruehwirth) writes:
>In PROLOG Digest Vol 6 Issue 52 of Fri, 22 july 88
>Richard O'Keefe comments on different versions of permute/2
>and their efficiency.

>Still, there is another slightly more
>intuitive version equivalent to /*3*/ in behaviour and timing:
>
>/*4*/	permute4(L1,L2) :- 
>		same_length(L1,L2),
>		permute2(L1,L2).
>
>/* permute2/2 as version /*2*/ */
>
>	same_length([],[]).
>	same_length([_|L1],[_|L2]) :- same_length(L1,L2).
>
This is what the Quintus Prolog library predicate permutation/2 used to
do.  It's a neat hack which I learned from Ed Stabler.  The version I
recommended in V6I52 has replaced it, being faster.  But the two are
very close: each step of version /*3*/ does one step of version /*2*/
and one step of same_length.

>Last, let me suggest a problem:
>Is it possible to write a predicate permute/2 (calling permute/n)
>equivalent to standard permutation (version /*2*/) without using
>select/3?  Of course I dont mean just wrapping normal permute/2
>and select/3 with permute/n.  I mean something like:
>/*6*/  permute(L1,L2) :- permute(L1,L2,...).
>/* Code of permute/n and nothing else */

I don't know whether this is what Fruehwirth had in mind, but it seems
to meet his conditions.

perm([], []).
perm([H|T], [X|P]) :-
	perm(T, H, Q, Q, X, P).

perm(T, H, T, [], H, []).
perm(T, H, T, [G|L], H, [X|P]) :-
	perm(L, G, Q, Q, X, P).
perm([H|T], G, [G|L], Q, X, P) :-
	perm(T, H, L, Q, X, P).

This rather confusing piece of code was obtained by starting with

perm([], []).
perm([H|T], [X|P]) :-
	select(X, [H|T], Q),
	perm(Q, P).

then introducing a new predicate

perm(T, H, L, Q, X, P) :-
	select(X, [H|T], L),
	perm(Q, P).

This gives us

perm([], []).
perm([H|T], [X|P]) :-
	perm(T, H, Q, Q, X, P).

as the definition of perm/2.

I then unfolded

select(X, [X|L], L).
select(X, [H|T], [H|L]) :-
	select(X, T, L).

in perm/6, getting the clauses

perm(T, H, T, Q, H, P) :-
	perm(Q, P).
perm(T, H, [H|L1], Q, X, P) :-
	select(X, T, L1),
	perm(Q, P).

Since select(_, L, _) can only succeed when L is a cons cell, we can
make that explicit, and write the second clause as

perm([H1|T1], H, [H|L1], Q, X, P) :-
	select(X, [H1|T1], L1),
	perm(Q, P).
	
But the body of this is just perm/6 all over again, so folding gives us

perm(T, H, T, Q, H, P) :-
	perm(Q, P).
perm([H|T], G, [G|L], Q, X, P) :-
	perm(T, H, L, Q, X, P).

We're still not quite there.  The last step is to unfold perm/2 in the
first clause.  We get two cases:

perm(T, H, T, [], H, []).
perm(T, H, T, [H1|T1], H, [X|P]) :-
	perm(T1, H1, Q, Q, X, P).

The final result was shown above.  We could even add another argument
to it (using the original P as a counter) to make it work both ways around.

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.
Technical Details
Message-ID: <209@quintus.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!cornell!uw-beaver!teknowledge-vaxc!sri-unix!quintus!ok
References: <1074@tuhold>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!cornell!uw-beaver!teknowledge-vaxc!sri-unix!quintus!ok
From: ok@quintus.uucp (Richard A. O'Keefe)
Newsgroups: comp.lang.prolog
Subject: Re: permutation - versions and their efficiency
Message-ID: <209@quintus.UUCP>
Date: 29 Jul 88 22:43:58 GMT
References: <1074@tuhold>
Sender: news@quintus.UUCP
Reply-To: ok@quintus.UUCP (Richard A. O'Keefe)
Organization: Quintus Computer Systems, Inc.
Lines: 106