from sympy.combinatorics.permutations import Permutation from sympy.core.symbol import symbols from sympy.matrices import Matrix from sympy.utilities.iterables import variations, rotate_left def symmetric(n): """ Generates the symmetric group of order n, Sn. Examples ======== >>> from sympy.combinatorics.generators import symmetric >>> list(symmetric(3)) [(2), (1 2), (2)(0 1), (0 1 2), (0 2 1), (0 2)] """ for perm in variations(range(n), n): yield Permutation(perm) def cyclic(n): """ Generates the cyclic group of order n, Cn. Examples ======== >>> from sympy.combinatorics.generators import cyclic >>> list(cyclic(5)) [(4), (0 1 2 3 4), (0 2 4 1 3), (0 3 1 4 2), (0 4 3 2 1)] See Also ======== dihedral """ gen = list(range(n)) for i in range(n): yield Permutation(gen) gen = rotate_left(gen, 1) def alternating(n): """ Generates the alternating group of order n, An. Examples ======== >>> from sympy.combinatorics.generators import alternating >>> list(alternating(3)) [(2), (0 1 2), (0 2 1)] """ for perm in variations(range(n), n): p = Permutation(perm) if p.is_even: yield p def dihedral(n): """ Generates the dihedral group of order 2n, Dn. The result is given as a subgroup of Sn, except for the special cases n=1 (the group S2) and n=2 (the Klein 4-group) where that's not possible and embeddings in S2 and S4 respectively are given. Examples ======== >>> from sympy.combinatorics.generators import dihedral >>> list(dihedral(3)) [(2), (0 2), (0 1 2), (1 2), (0 2 1), (2)(0 1)] See Also ======== cyclic """ if n == 1: yield Permutation([0, 1]) yield Permutation([1, 0]) elif n == 2: yield Permutation([0, 1, 2, 3]) yield Permutation([1, 0, 3, 2]) yield Permutation([2, 3, 0, 1]) yield Permutation([3, 2, 1, 0]) else: gen = list(range(n)) for i in range(n): yield Permutation(gen) yield Permutation(gen[::-1]) gen = rotate_left(gen, 1) def rubik_cube_generators(): """Return the permutations of the 3x3 Rubik's cube, see https://www.gap-system.org/Doc/Examples/rubik.html """ a = [ [(1, 3, 8, 6), (2, 5, 7, 4), (9, 33, 25, 17), (10, 34, 26, 18), (11, 35, 27, 19)], [(9, 11, 16, 14), (10, 13, 15, 12), (1, 17, 41, 40), (4, 20, 44, 37), (6, 22, 46, 35)], [(17, 19, 24, 22), (18, 21, 23, 20), (6, 25, 43, 16), (7, 28, 42, 13), (8, 30, 41, 11)], [(25, 27, 32, 30), (26, 29, 31, 28), (3, 38, 43, 19), (5, 36, 45, 21), (8, 33, 48, 24)], [(33, 35, 40, 38), (34, 37, 39, 36), (3, 9, 46, 32), (2, 12, 47, 29), (1, 14, 48, 27)], [(41, 43, 48, 46), (42, 45, 47, 44), (14, 22, 30, 38), (15, 23, 31, 39), (16, 24, 32, 40)] ] return [Permutation([[i - 1 for i in xi] for xi in x], size=48) for x in a] def rubik(n): """Return permutations for an nxn Rubik's cube. Permutations returned are for rotation of each of the slice from the face up to the last face for each of the 3 sides (in this order): front, right and bottom. Hence, the first n - 1 permutations are for the slices from the front. """ if n < 2: raise ValueError('dimension of cube must be > 1') # 1-based reference to rows and columns in Matrix def getr(f, i): return faces[f].col(n - i) def getl(f, i): return faces[f].col(i - 1) def getu(f, i): return faces[f].row(i - 1) def getd(f, i): return faces[f].row(n - i) def setr(f, i, s): faces[f][:, n - i] = Matrix(n, 1, s) def setl(f, i, s): faces[f][:, i - 1] = Matrix(n, 1, s) def setu(f, i, s): faces[f][i - 1, :] = Matrix(1, n, s) def setd(f, i, s): faces[f][n - i, :] = Matrix(1, n, s) # motion of a single face def cw(F, r=1): for _ in range(r): face = faces[F] rv = [] for c in range(n): for r in range(n - 1, -1, -1): rv.append(face[r, c]) faces[F] = Matrix(n, n, rv) def ccw(F): cw(F, 3) # motion of plane i from the F side; # fcw(0) moves the F face, fcw(1) moves the plane # just behind the front face, etc... def fcw(i, r=1): for _ in range(r): if i == 0: cw(F) i += 1 temp = getr(L, i) setr(L, i, list(getu(D, i))) setu(D, i, list(reversed(getl(R, i)))) setl(R, i, list(getd(U, i))) setd(U, i, list(reversed(temp))) i -= 1 def fccw(i): fcw(i, 3) # motion of the entire cube from the F side def FCW(r=1): for _ in range(r): cw(F) ccw(B) cw(U) t = faces[U] cw(L) faces[U] = faces[L] cw(D) faces[L] = faces[D] cw(R) faces[D] = faces[R] faces[R] = t def FCCW(): FCW(3) # motion of the entire cube from the U side def UCW(r=1): for _ in range(r): cw(U) ccw(D) t = faces[F] faces[F] = faces[R] faces[R] = faces[B] faces[B] = faces[L] faces[L] = t def UCCW(): UCW(3) # defining the permutations for the cube U, F, R, B, L, D = names = symbols('U, F, R, B, L, D') # the faces are represented by nxn matrices faces = {} count = 0 for fi in range(6): f = [] for a in range(n**2): f.append(count) count += 1 faces[names[fi]] = Matrix(n, n, f) # this will either return the value of the current permutation # (show != 1) or else append the permutation to the group, g def perm(show=0): # add perm to the list of perms p = [] for f in names: p.extend(faces[f]) if show: return p g.append(Permutation(p)) g = [] # container for the group's permutations I = list(range(6*n**2)) # the identity permutation used for checking # define permutations corresponding to cw rotations of the planes # up TO the last plane from that direction; by not including the # last plane, the orientation of the cube is maintained. # F slices for i in range(n - 1): fcw(i) perm() fccw(i) # restore assert perm(1) == I # R slices # bring R to front UCW() for i in range(n - 1): fcw(i) # put it back in place UCCW() # record perm() # restore # bring face to front UCW() fccw(i) # restore UCCW() assert perm(1) == I # D slices # bring up bottom FCW() UCCW() FCCW() for i in range(n - 1): # turn strip fcw(i) # put bottom back on the bottom FCW() UCW() FCCW() # record perm() # restore # bring up bottom FCW() UCCW() FCCW() # turn strip fccw(i) # put bottom back on the bottom FCW() UCW() FCCW() assert perm(1) == I return g