ref: 2183f9eaeca9fb5d57b637c15707e663caf33575
dir: /appl/math/perms.b/
#
# initially generated by c2l
#
implement Perms;
include "draw.m";
Perms: module
{
init: fn(nil: ref Draw->Context, argl: list of string);
};
include "sys.m";
sys: Sys;
init(nil: ref Draw->Context, argl: list of string)
{
sys = load Sys Sys->PATH;
main(len argl, argl);
}
#
# * generate permutations of N elements
# * from ``On Programming, an interim report on the SETL project'',
# * Jacob T Schwartz (ed), New York University
#
Seq: adt{
nel: int;
el: array of int;
};
origin: int = 1;
main(argc: int, argv: list of string): int
{
n: int;
if(argc > 1 && (as := hd tl argv)[0] == '-'){
origin = int (as[1: ]);
argc--;
argv = tl argv;
}
if(argc != 2){
sys->fprint(sys->fildes(2), "Usage: perms #elements\n");
exit;
}
n = int hd tl argv;
if(n > 0)
perms(n);
exit;
}
perms(n: int)
{
seq: ref Seq;
seq = newseq(n);
do
putseq(seq);
while(eperm(seq) != nil);
}
putseq(seq: ref Seq)
{
k: int;
for(k = 0; k < seq.nel; k++)
sys->print(" %d", seq.el[k]+origin);
sys->print("\n");
}
eperm(seq: ref Seq): ref Seq
{
j, k, n: int;
n = seq.nel;
# if sequence is monotone decreasing, there are no more
# permutations. Otherwise, find last point of increase
hit := 0;
for(j = n-2; j >= 0; j--)
if(seq.el[j] < seq.el[j+1]){
hit = 1;
break;
}
if(!hit)
return nil;
# then find the last seq[k] which exceeds seq[j] and swop
for(k = seq.nel-1; k > j; k--)
if(seq.el[k] > seq.el[j]){
{
t: int;
t = seq.el[k];
seq.el[k] = seq.el[j];
seq.el[j] = t;
}
;
break;
}
# then re-arrange all the elements from seq[j+1] into
# increasing order
for(k = j+1; k < (n+j+1)/2; k++){
kk: int;
kk = n-k+j;
{
t: int;
t = seq.el[k];
seq.el[k] = seq.el[kk];
seq.el[kk] = t;
}
;
}
return seq;
}
newseq(n: int): ref Seq
{
seq: ref Seq;
k: int;
seq = ref Seq;
seq.nel = n;
seq.el = array[n] of int;
for(k = 0; k < n; k++)
seq.el[k] = k;
return seq;
}