Returning a matrix rotated by 90, 180, and 270 degrees in APL with outer product

I am trying to write some APL code that will take a matrix and give back the matrix and all its 90 degree rotations.

As a rotation function I have: {(⌽∘⍉)⍣⍺⊢⍵} , which takes a matrix on the right and number of CW rotations on the left, and it seems to work fine on its own.

To generate all 4 output arrays, I have tried to use the outer product like this:

r ← {(⌽∘⍉)⍣⍺⊢⍵}
mat2 ← (2 2 ⍴ ⍳4)

0 1 2 3  ∘.r mat2

But it doesn't work, only returning the base array 4 times. I expected it to use the left terms as left arguments applied individually to the right argument.

However, when I give more than one argument on the right, it seems to do what I want - here it does the 0 and 90 degree rotation to a 2x2 and 3x3 matrix:

mat2 ← (2 2 ⍴ ⍳4)
mat3 ← (3 3 ⍴ ⍳9)

⍝ This does what I was expecting
       0 1 ∘.r mat2 mat3

┌───┬─────┐
│1 2│1 2 3│
│3 4│4 5 6│
│   │7 8 9│
├───┼─────┤
│3 1│7 4 1│
│4 2│8 5 2│
│   │9 6 3│
└───┴─────┘

⍝ This just gives me back the same array twice
      0 1 ∘.r mat2 
1 2
3 4
   
1 2
3 4

I am quite new to APL, so I'm not sure if I'm getting the outer product or the power operator usage wrong. Applying the shape operator to the above outputs is also showing me something different than I was expecting:

    ⍴ 0 1 ∘.r mat2 mat3
2 2

    ⍴ 0 1 ∘.r mat2 
2 2 2

So it seems the case with two input arrays is giving me a 2x2 array where each element is a rotated array, which is what I was expecting. But the case with one input array is giving me a 2x2x2 (4x2x2 if I use all 4 rotations) array of numbers. I'm not sure what's causing the difference in structure here with 1 vs more right arguments. I'm too bothered by which of these structures I'd end up with, but I don't know where the difference is coming from.


What you need is

0 1 2 3  ∘.r ⊂mat2

or

0 1 2 3  r¨ ⊂mat2

What 0 1 2 3 ∘.r mat2 is doing can be inspected with this snippet:

      0 1 2 3  ∘.{⎕←'⍺:'⍺'⍵:'⍵⋄⍺⍵} mat2                                                                                                                                                      
 ⍺:  0  ⍵:  1
 ⍺:  0  ⍵:  2
 ⍺:  0  ⍵:  3
 ⍺:  0  ⍵:  4
 ⍺:  1  ⍵:  1
 ⍺:  1  ⍵:  2
 ⍺:  1  ⍵:  3
 ⍺:  1  ⍵:  4
 ⍺:  2  ⍵:  1
 ⍺:  2  ⍵:  2
 ⍺:  2  ⍵:  3
 ⍺:  2  ⍵:  4
 ⍺:  3  ⍵:  1
 ⍺:  3  ⍵:  2
 ⍺:  3  ⍵:  3
 ⍺:  3  ⍵:  4

What is happening is that each of 0 1 2 3 is being zipped with each element of mat2. Rotating a single number will not change its orientation, so you're getting multiple copies of the same matrix.

A good resource for understanding this behaviour is the APL Wiki Outer Product page.

What you need is to zip each of 0 1 2 3 with the whole of mat2 i.e. you need to enclose it with so it gets treated as a single object. Then you will get the rotations you need.