Quick followup on previous notes. It's possible to generate a rotation matrix in K without any list appending functions. No idea if it's faster, and don't particularly care, but this way just feels righter.
I rewrote rots
to be a matrix of indices that can be projected across a real array, rather than a direct rotation of it. rots[x;y]
generates y rows of rightward rotations of a x-sized array. I also made an inclusive rotsi
function which leaves the first row unchanged. Maybe that one is easier to visualize.
rotsi[5;6]
0 1 2 3 4
4 0 1 2 3
3 4 0 1 2
2 3 4 0 1
1 2 3 4 0
0 1 2 3 4
rots[5;6]
4 0 1 2 3
3 4 0 1 2
2 3 4 0 1
1 2 3 4 0
0 1 2 3 4
4 0 1 2 3
rotsi
is implemented in terms of rots
, which is implemented with the enumeration !
operator.
Since the resulting matrix will be y×x items long, it makes sense to begin by enumerating that many.
{!x*y}[5;6]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Then cut it into y rows.
{y^!x*y}[5;6]
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25 26 27 28 29
The shape is there. A modulo operation against x will give the indices of 0…x-1. K has a builtin mod
function, but it gives me weird errors when currying, so here's my (stackoverflow's) version.
md:{y-x*_y%x }
{(md[x])'y^!x*y}[5;6]
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
Getting there, just gotta spin it. The order of each row is the same at the moment, but it wouldn't be if we added a different amount to each one before the modulo. There are six rows, so what about adding 0…5?
{(md[x])'(!y)+y^!x*y}[5;6]
0 1 2 3 4
1 2 3 4 0
2 3 4 0 1
3 4 0 1 2
4 0 1 2 3
0 1 2 3 4
Almost. Would work if the matrix were a perfect square. Try it with a larger offset of 1…6.
{(md[x])'(1+!y)+y^!x*y}[5;6]
1 2 3 4 0
2 3 4 0 1
3 4 0 1 2
4 0 1 2 3
0 1 2 3 4
1 2 3 4 0
Definitely spinning now, just not in the right order. Generalized, we need to add an iteration vector of the difference between x and y to apply the correct offset.
{(md[x])'((x-y)+!y)+y^!x*y}[5;4]
1 2 3 4 0
2 3 4 0 1
3 4 0 1 2
4 0 1 2 3
Reversing this offset vector changes the rotation direction.
rots:{(md[x])'(|(x-y)+!y)+y^!x*y};rots[5;6]
4 0 1 2 3
3 4 0 1 2
2 3 4 0 1
1 2 3 4 0
0 1 2 3 4
4 0 1 2 3
The inclusive rotation matrix is self-explanatory.
rotsi:{(,!x),rots[x;y-1]};rotsi[5;6]
0 1 2 3 4
4 0 1 2 3
3 4 0 1 2
2 3 4 0 1
1 2 3 4 0
0 1 2 3 4
+/:\:
rots
and rotsi
should be general functions where a negative x rotates left, and a positive right.rot
.Observe.
rotsli:{md[y]'(!x)+/:\:!y}
rotsl:{1_rotsli[x+1;y]}
rotsr:{md[y]'(|(y-x)+!x)+/:\:!y}
rotsri:{(,!y),rotsr[x-1;y]}
rots:{$[x<0;rotsl[abs x;y];rotsr[x;y]]}
rotsi:{$[x<0;rotsli[abs x;y];rotsri[x;y]]}
rot:{y[,/((abs x)-1)_(rots[x;#y])]}
rotsi[-8;5]
0 1 2 3 4
1 2 3 4 0
2 3 4 0 1
3 4 0 1 2
4 0 1 2 3
0 1 2 3 4
1 2 3 4 0
2 3 4 0 1
rotsi[8;5]
0 1 2 3 4
4 0 1 2 3
3 4 0 1 2
2 3 4 0 1
1 2 3 4 0
0 1 2 3 4
4 0 1 2 3
3 4 0 1 2
xs:"hello"
rot[-1;xs]
"elloh"
rot[1;xs]
"ohell"
See my kool repo for these procedures, among others.