Subject: Better implementation of random_permutation
From: Robert Dodier
Date: Thu, 20 Jan 2011 14:28:33 -0700
Hmm, this is the same Knuth shuffle expressed in a different way,
right? If so the only problem I see is that the random numbers should
come from Maxima's $RANDOM and not CL RANDOM (so that random_permutation
respects the seed the user sets, if any).
Thanks for taking a look at it --
Robert Dodier
On 1/20/11, Mark H Weaver <mhw at netris.org> wrote:
>> The code for random_permutation is in maxima/src/nset.lisp:
>>
>> (defun $random_permutation (a)
>> (if ($listp a)
>> (setq a (copy-list (cdr a)))
>> (setq a (copy-list (require-set a "$random_permutation"))))
>>
>> (let ((n (length a)))
>> (dotimes (i n)
>> (let
>> ((j (+ i ($random (- n i))))
>> (tmp (nth i a)))
>> (setf (nth i a) (nth j a))
>> (setf (nth j a) tmp))))
>>
>> `((mlist) , at a))
>
> Note that the implementation above is quite slow, O(n^2).
> Here's a much faster O(n) version:
>
> (defun $random_permutation (arg)
> (let* ((lst (if ($listp arg)
> (cdr arg)
> (require-set arg "$random_permutation")))
> (a (make-array (length lst))))
> (loop for x in lst
> and i from 0
> do (shiftf (svref a i)
> (svref a (random (1+ i)))
> x))
> (cons '(mlist)
> (loop for x across a
> collect x))))
>
> On my system (Maxima 5.23.2 on GCL 2.6.7 on a Loongson processor),
> this version runs about 46 times faster on a list of length 1000.
>
> Any objections to me committing this change to the trunk?
>
> Mark
>
>
> PS: here's equivalent pseudo-code for the new version:
>
> random_permutation(array b)
> {
> n <-- length(b);
> a <-- new_array(n);
> for i from 0 to n-1 do
> {
> j <-- random integer (such that 0 <= j <= i);
> a[i] <-- a[j];
> a[j] <-- b[i];
> }
> return(a);
> }
> _______________________________________________
> Maxima mailing list
> Maxima at math.utexas.edu
> http://www.math.utexas.edu/mailman/listinfo/maxima
>