I decided to post another answer. My first answer was very simple, but not completely in the spirit of the question. I think I now have a better answer, having thought a little.
TL DR The following code rotates the polycube throughout all 24 cube rotations. This happens without matrix multiplication; instead, the 3x3x3x3x3 index table is used, which gives several key index rotations in a polycube, and a Gray code of length 23 for the cube rotation group. It has only six real lines of code, almost all of which are for loops. It is very fast and quite compact (with the exception of the index table, which can be generated by the program (see below)).
import numpy as np
My solution is to find the Gray code for the cube rotation group.
First, we need to find a good idea for the rotation group you are using. Consider a 2x2x2 cube with 1x1x1 cubes labeled as follows:
1 2 3 4 4 3 2 1
We start with 1 to fit the math literature. The top left square should be the front panel, and the bottom right square should be the back. Imagine 1 connected by edges with 2 and 3 on the front surface, with 4 on the back surface, etc.
Note that diagonally opposite cubes have the same number. Now any rotation of the cube corresponds to a rearrangement of four numbers on the front side. In addition, any rearrangement of numbers on the front side corresponds to a rotation. Four Z-axis turns coming out of a page,
1 2 3 1 4 3 2 4 3 4 4 3 4 2 2 4 2 1 1 2 1 3 3 1 2 1 1 3 3 4 4 2
We can mark the turns on the effect on the front side. These are 1234, 3142, 4321 and 2413.
Three additional rotations about the x axis (plus the single rotation we start from)
1 2 3 4 2 1 4 3 3 4 4 3 2 1 1 2 4 3 3 4 1 2 2 1 2 1 4 3 1 2 3 4
In our more compact designations, additional rotations are 3421, 2143 and 4312.
Three additional rotations around the Y axis
1 2 2 3 3 4 4 1 3 4 4 3 4 1 1 4 1 2 2 1 2 3 3 2 2 1 3 2 4 3 1 4
In compact recording, three additional turns - 2341, 3412 and 4123.
There are three turns, including identity, that fix 1 diagonal:
1 2 1 4 1 3 3 4 4 3 2 3 3 2 4 2 2 4 2 1 4 1 3 1
with the new labeled 1423 and 1342.
There are three turns, including identity, that capture 2 diagonals:
1 2 4 2 3 2 3 4 4 3 1 3 3 1 4 1 1 4 2 1 2 4 2 3
with new labeled 4213 and 3241.
There are three turns, including identity, that capture 3 diagonals:
1 2 2 4 4 1 3 4 4 3 3 1 1 3 3 2 2 3 2 1 4 2 1 4
with new labeled 2431 and 4132.
There are three turns, including identity, that capture 4 diagonals:
1 2 2 3 3 1 3 4 4 3 1 4 4 1 2 4 4 2 2 1 3 2 1 3
with new ones marked 2314 and 3124.
Finally, there are six marginal flips plus personality. 1-2 flips
1 2 2 1 3 4 4 3 3 4 4 3 2 1 1 2
with the new one, presented in 2134. Similarly, there are edges along the edges 1-3 (3214), 1-4 (4231), 2-3 (1324), 2-4 (1432) and 3-4 (1243),
Each of the 24 rotations corresponds to a separate permutation of 1234, and since there are 24 permutations and 24 rotations, each individual permutation corresponds to a rotation. We say that the cube rotation group and the permutation group S_4 of 1234 are isomorphic . (One way of thinking about this is that cube rotations act like a permutation of the cube's diagonals, and the correspondence is 1-1.)
We could figure out the effect of each of the 24 rotations on your arrays, but this is tedious and error prone. Instead, we will see that a group of rotations is generated by just three rotations, the edge flips over
R1=transpose numbers in position2 1 and 2, and leave numbers in positions 3 and 4 alone R2=transpose numbers in positions 2 and 3, and leave numbers in positions 1 and 4 alone R3=transpose numbers in positions 3 and 4, and leave numbers in positions 1 and 2 alone
and their compositions. We will add
R0=identity operation
for completeness. Using only these three generators, we can find the Hamiltonian chain through the Cayley graph of the rotation group:
01 1234 apply R0 to starting position, ie, do nothing 02 1243 apply R3 to previous 03 1423 apply R2 to previous 04 4123 R1 05 4213 R2 06 2413 R1 07 2143 R2 08 2134 R3 09 2314 R2 10 2341 R3 11 2431 R2 12 4231 R1 13 4321 R2 14 3421 R1 15 3241 R2 16 3214 R3 17 3124 R2 18 3142 R3 19 3412 R2 20 4312 R1 21 4132 R2 22 1432 R1 23 1342 R2 24 1324 R3
Note that each permutation (i.e., rotation of the cube) appears on this list exactly once, and that the transition from one element in the list to the next is performed by transposing the elements in positions 1-2, 2-3, or 3. -4 , which corresponds to the rotation of the edges R1, R2 and R3. This Gray code for S_4 (and much more, which, unfortunately, is quite difficult to understand if you do not know about reflection groups and Coxeter diagrams), is presented in the famous article “ Gray codes for reflection groups” by Conway, Sloan, and Wilkes .
Gray's code is summed up by this sequence of 23 numbers:
gray = {3,2,1,2,1,2,3,2,3,2,1,2,1,2,3,2,3,2,1,2,1,2,3}
Thus, we have significantly reduced the amount of work we have to do, starting from calculating the effect of 24 different rotations on a 2x2x2 polycube (and then on a 3x3x3 polycube), to measuring the effect of only 3 different rotations on our cubes. These three rotation functions can be stored in an array with index 0..3, and then applied as
nextConfiguration = currentConfiguration.Rotation[gray[i]]
(Please note that we can even get all 48 reflections / turns if we want, following this rotation sequence with one reflection P (any reflection will do, so choose the simplest one to implement), and then following this reflection with a gray sequence in the reverse order, which gives Gray code for a complete group of 48 reflections / rotations (building large sequences by attaching the reverse sequence to yourself is one of the “big ideas” when building Gray codes.))
We have come a long way without even considering the representation of the shapes you want to rotate, but now we need to implement R1, R2 and R3, so we need to consider the data structure that represents the shapes, a three-dimensional array. Consider the effect of R1, turning the rib 180 degrees on the axis through the midpoints of 1-2 ribs, on our 2x2x2 array:
(0,0,0) (1,0,0) (1,0,0) (0,0,0) (0,1,0) (1,1,0) (0,0,1) (1,0,1)
This tells us that our operation R1 can be implemented
output(0,0,0) = input(1,0,0) output(1,0,0) = input(0,0,0) output(0,1,0) = input(1,0,1) output(1,1,0) = input(0,0,1) output(0,0,1) = input(1,1,0) output(1,0,1) = input(0,1,0) output(0,1,1) = input(1,1,1) output(1,1,1) = input(0,1,1)
This defines the operation R1 in the case of 2x2x2. It should be clear how to determine R2 and R3 in the case of 2x2x2, as well as how to determine these operations in the case of 3x3x3.
Let me conclude by saying that defining the Ri operators is tedious and error prone, so we don’t want to do this too much if we can help. We can avoid the definition of only two operators, R1 (already defined above) and F, the rotation of the front face:
(0,0,0) (1,0,0) (0,1,0) (0,0,0) (0,1,0) (1,1,0) (0,0,1) (1,0,1)
Then we can represent R2 = FFFR1.F (where. It means "followed by"), and R3 = FFR1.FF (these are the "conjugates" of R1.)
For the 3x3x3 case, it's some work to find index tables manually, so I wrote a procedure for that, and then I found all 24 rotations of the alphabetical cube. See the code below. I'm sure a Python expert can make it much shorter. Python.
, 333, .
import numpy as np
[[['a' 'b' 'c'] ['d' 'e' 'f'] ['g' 'h' 'i']] [['j' 'k' 'l'] ['m' '+' 'n'] ['o' 'p' 'q']] [['r' 's' 't'] ['u' 'v' 'w'] ['x' 'y' 'z']]] ----------------- [[['z' 'w' 't'] ['y' 'v' 's'] ['x' 'u' 'r']] [['q' 'n' 'l'] ['p' '+' 'k'] ['o' 'm' 'j']] [['i' 'f' 'c'] ['h' 'e' 'b'] ['g' 'd' 'a']]] ----------------- [[['x' 'o' 'g'] ['y' 'p' 'h'] ['z' 'q' 'i']] [['u' 'm' 'd'] ['v' '+' 'e'] ['w' 'n' 'f']] [['r' 'j' 'a'] ['s' 'k' 'b'] ['t' 'l' 'c']]] ----------------- [[['r' 's' 't'] ['j' 'k' 'l'] ['a' 'b' 'c']] [['u' 'v' 'w'] ['m' '+' 'n'] ['d' 'e' 'f']] [['x' 'y' 'z'] ['o' 'p' 'q'] ['g' 'h' 'i']]] ----------------- [[['a' 'd' 'g'] ['j' 'm' 'o'] ['r' 'u' 'x']] [['b' 'e' 'h'] ['k' '+' 'p'] ['s' 'v' 'y']] [['c' 'f' 'i'] ['l' 'n' 'q'] ['t' 'w' 'z']]] ----------------- [[['c' 'l' 't'] ['f' 'n' 'w'] ['i' 'q' 'z']] [['b' 'k' 's'] ['e' '+' 'v'] ['h' 'p' 'y']] [['a' 'j' 'r'] ['d' 'm' 'u'] ['g' 'o' 'x']]] ----------------- [[['i' 'h' 'g'] ['f' 'e' 'd'] ['c' 'b' 'a']] [['q' 'p' 'o'] ['n' '+' 'm'] ['l' 'k' 'j']] [['z' 'y' 'x'] ['w' 'v' 'u'] ['t' 's' 'r']]] ----------------- [[['r' 'u' 'x'] ['s' 'v' 'y'] ['t' 'w' 'z']] [['j' 'm' 'o'] ['k' '+' 'p'] ['l' 'n' 'q']] [['a' 'd' 'g'] ['b' 'e' 'h'] ['c' 'f' 'i']]] ----------------- [[['t' 'l' 'c'] ['s' 'k' 'b'] ['r' 'j' 'a']] [['w' 'n' 'f'] ['v' '+' 'e'] ['u' 'm' 'd']] [['z' 'q' 'i'] ['y' 'p' 'h'] ['x' 'o' 'g']]] ----------------- [[['g' 'h' 'i'] ['o' 'p' 'q'] ['x' 'y' 'z']] [['d' 'e' 'f'] ['m' '+' 'n'] ['u' 'v' 'w']] [['a' 'b' 'c'] ['j' 'k' 'l'] ['r' 's' 't']]] ----------------- [[['x' 'u' 'r'] ['o' 'm' 'j'] ['g' 'd' 'a']] [['y' 'v' 's'] ['p' '+' 'k'] ['h' 'e' 'b']] [['z' 'w' 't'] ['q' 'n' 'l'] ['i' 'f' 'c']]] ----------------- [[['z' 'q' 'i'] ['w' 'n' 'f'] ['t' 'l' 'c']] [['y' 'p' 'h'] ['v' '+' 'e'] ['s' 'k' 'b']] [['x' 'o' 'g'] ['u' 'm' 'd'] ['r' 'j' 'a']]] ----------------- [[['t' 's' 'r'] ['w' 'v' 'u'] ['z' 'y' 'x']] [['l' 'k' 'j'] ['n' '+' 'm'] ['q' 'p' 'o']] [['c' 'b' 'a'] ['f' 'e' 'd'] ['i' 'h' 'g']]] ----------------- [[['c' 'f' 'i'] ['b' 'e' 'h'] ['a' 'd' 'g']] [['l' 'n' 'q'] ['k' '+' 'p'] ['j' 'm' 'o']] [['t' 'w' 'z'] ['s' 'v' 'y'] ['r' 'u' 'x']]] ----------------- [[['a' 'j' 'r'] ['b' 'k' 's'] ['c' 'l' 't']] [['d' 'm' 'u'] ['e' '+' 'v'] ['f' 'n' 'w']] [['g' 'o' 'x'] ['h' 'p' 'y'] ['i' 'q' 'z']]] ----------------- [[['z' 'y' 'x'] ['q' 'p' 'o'] ['i' 'h' 'g']] [['w' 'v' 'u'] ['n' '+' 'm'] ['f' 'e' 'd']] [['t' 's' 'r'] ['l' 'k' 'j'] ['c' 'b' 'a']]] ----------------- [[['i' 'f' 'c'] ['q' 'n' 'l'] ['z' 'w' 't']] [['h' 'e' 'b'] ['p' '+' 'k'] ['y' 'v' 's']] [['g' 'd' 'a'] ['o' 'm' 'j'] ['x' 'u' 'r']]] ----------------- [[['r' 'j' 'a'] ['u' 'm' 'd'] ['x' 'o' 'g']] [['s' 'k' 'b'] ['v' '+' 'e'] ['y' 'p' 'h']] [['t' 'l' 'c'] ['w' 'n' 'f'] ['z' 'q' 'i']]] ----------------- [[['x' 'y' 'z'] ['u' 'v' 'w'] ['r' 's' 't']] [['o' 'p' 'q'] ['m' '+' 'n'] ['j' 'k' 'l']] [['g' 'h' 'i'] ['d' 'e' 'f'] ['a' 'b' 'c']]] ----------------- [[['g' 'd' 'a'] ['h' 'e' 'b'] ['i' 'f' 'c']] [['o' 'm' 'j'] ['p' '+' 'k'] ['q' 'n' 'l']] [['x' 'u' 'r'] ['y' 'v' 's'] ['z' 'w' 't']]] ----------------- [[['i' 'q' 'z'] ['h' 'p' 'y'] ['g' 'o' 'x']] [['f' 'n' 'w'] ['e' '+' 'v'] ['d' 'm' 'u']] [['c' 'l' 't'] ['b' 'k' 's'] ['a' 'j' 'r']]] ----------------- [[['c' 'b' 'a'] ['l' 'k' 'j'] ['t' 's' 'r']] [['f' 'e' 'd'] ['n' '+' 'm'] ['w' 'v' 'u']] [['i' 'h' 'g'] ['q' 'p' 'o'] ['z' 'y' 'x']]] ----------------- [[['t' 'w' 'z'] ['l' 'n' 'q'] ['c' 'f' 'i']] [['s' 'v' 'y'] ['k' '+' 'p'] ['b' 'e' 'h']] [['r' 'u' 'x'] ['j' 'm' 'o'] ['a' 'd' 'g']]] ----------------- [[['g' 'o' 'x'] ['d' 'm' 'u'] ['a' 'j' 'r']] [['h' 'p' 'y'] ['e' '+' 'v'] ['b' 'k' 's']] [['i' 'q' 'z'] ['f' 'n' 'w'] ['c' 'l' 't']]]