This is my attempt, which appears to have a bug, but I don't see where it is exactly. If you see it, please let me know where it is.
First, let's follow the algorithm sketched by Wikipedia for N<5:
super([X], [X], 1).
super([X|Xs], Super, N) :-
%% obtain the superpermutation of N-1
super(Xs, Super0, N0),
succ(N0, N),
%% split Super0 into its individual permutations
split_permutations(N0, Super0, Permutations),
%% insert X into the middle of a copy of each of these
maplist(insert_surrounded(X), Permutations, NewPermutations),
%% concatenate the new permutations and deduplicate them
append(NewPermutations, SuperWithDupes),
deduplicate(SuperWithDupes, Super).
Now to make this go, we will need quite a few utility predicates, starting with deduplication and testing whether a sublist is a permutation:
deduplicate([X], [X]).
deduplicate([X,Y|Xs], Dedup) :-
(X == Y ->
deduplicate([Y|Xs], Dedup)
;
deduplicate([Y|Xs], Dedup1),
Dedup = [X|Dedup1]
).
is_unique([]).
is_unique([X|Xs]) :-
\+ memberchk(X, Xs),
is_unique(Xs).
Now to obtain the permutations from the N-1 call, I have split_permutations/3
which gives you back the permutations (in order) of an earlier call to super/2
:
split_permutations(_, [], []).
split_permutations(Length, [X|Xs], Permutations) :-
split_permutations(Length, Xs, Permutations1),
length(L, Length),
(prefix(L, [X|Xs]), is_unique(L) ->
Permutations = [L|Permutations1]
;
Permutations = Permutations1
).
insert_surrounded/3
uses SWI-Prolog trick append/2
:
insert_surrounded(X, Permutation, NewPermutation) :-
append([Permutation, [X], Permutation], NewPermutation).
For my own edification, I wrote a thing to output a list slammed together so that I could compare my output to Wikipedia's:
write_string([]) :- nl.
write_string([X|Xs]) :- write(X), write_string(Xs).
For N=3, I get the same thing as Wikipedia:
?- super([3,2,1], X, Y), write_string(X).
123121321
X = [1, 2, 3, 1, 2, 1, 3, 2, 1],
Y = 3 .
I note with some dissatisfaction that using the first item in the list rather than the last is forcing me to present the input reversed. I would believe it if this was my problem with the next output, which is N=4:
- 12341232314231312431213421313241323214321 (mine)
- 123412314231243121342132413214321 (Wikipedia)
I am thinking now that it would have been better to generate some sort of superpermutation tree, and then have an output or serialization routine that handles the deduplication, and then constructing the tree leaves it in a broken-up state throughout the program until the last step. It seems inefficient and/or a good way to introduce bugs to do the concatenating and then immediately break the concatenated strings back apart. I don't think that is essential to the algorithm though. Perhaps another intrepid Prolog programmer will see a trick here!