Better implementation of random_permutation



> 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);
  }