Home > Net >  Shuffling multi-dimensional array in Common LISP
Shuffling multi-dimensional array in Common LISP

Time:10-30

I am trying to shuffle an (81 2 2) array, called patterns, in LISP. I used this code below, it compiles fine but when I try and run it I get this error: PATTERNS is an unknown keyword in LOOP macro. The call I make to this function is: (shuffle(list patterns))

(setq patterns (make-array '(81 2 2)
                          :initial-contents
                          '(((1.0 1.0) (0.0 0.0))
                            ((1.0 2.0) (0.0 1.0))
                            ((1.0 3.0) (0.0 1.0))
                            ((1.0 4.0) (0.0 1.0))...

(defun shuffle (patterns)
  (loop for i from (array-dimension patterns 0) downto 2
        do(
           (setq x (random 81))
           (setq y (random 81))
           
           (rotatef(aref patterns x 0 0)
                    (aref patterns y 0 0))
           (rotatef(aref patterns x 0 1)
                    (aref patterns y 0 1))
           (rotatef(aref patterns x 1 0)
                    (aref patterns y 1 0))
           (rotatef(aref patterns x 1 1)
                    (aref patterns y 1 1)))
        patterns)
  )

CodePudding user response:

; compilation unit finished
;   Undefined function:
;     I
;   caught 1 STYLE-WARNING condition

You are invoking function (I) in (elt patterns (i)). You need to remove the parentheses if you want to access the element at position i in patterns. You don't have an error at runtime because you never execute this expression.

(shuffle (list patterns))

The argument you give to shuffle is a list of one element, the array.

Since the length of the list is 1, the loop does nothing:

(loop for i from (length (list :something)) downto 2 collect i)
=> NIL

Finally, elt is used to access a sequence, either a list or a vector (an array of a single dimension). It is unclear what you are trying to achieve but you are supposed to access elements with (aref patterns ...) where ... stands for as many arguments as there are dimensions (here 3).

CodePudding user response:

As coredump pointed out you are just shuffling the list you wrapped your array in, which does not make much sense.

It seems that you do not want to shuffle the entire array but instead keep the rows intact and only shuffle the rows. For this, you still need to completely refer each cell, because multidimensional arrays in Common Lisp are not nested vectors.

You need the number of rows, which is (array-dimension array 0). Array indices go from 0 to one less than the size, so your Fisher-Yates loop should start there (you have an off-by-one error there). You need to go down to the second element, which has index 1 (again off-by-one). You need to determine a random element of those that have not been randomly determined yet, so your random range should only go up to including the current index (constant 80 is wrong). At each row, you need to loop and copy over the cells in that row. You can do that by either nested loops over the rest of the dimensions, or by calculating the indices yourself (maybe array-row-major-index helps for this) and using row-major-aref.

If instead you really want to shuffle the entire array without preserving rows, you can do a normal Fisher-Yates shuffle using array-total-size and row-major-aref.

  • Related