|
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)] |
|
""" |
|
yield from (Permutation(perm) for perm in variations(range(n), n)) |
|
|
|
|
|
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') |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
U, F, R, B, L, D = names = symbols('U, F, R, B, L, D') |
|
|
|
|
|
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) |
|
|
|
|
|
|
|
def perm(show=0): |
|
|
|
p = [] |
|
for f in names: |
|
p.extend(faces[f]) |
|
if show: |
|
return p |
|
g.append(Permutation(p)) |
|
|
|
g = [] |
|
I = list(range(6*n**2)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(n - 1): |
|
fcw(i) |
|
perm() |
|
fccw(i) |
|
assert perm(1) == I |
|
|
|
|
|
|
|
UCW() |
|
for i in range(n - 1): |
|
fcw(i) |
|
|
|
UCCW() |
|
|
|
perm() |
|
|
|
|
|
UCW() |
|
fccw(i) |
|
|
|
UCCW() |
|
assert perm(1) == I |
|
|
|
|
|
|
|
FCW() |
|
UCCW() |
|
FCCW() |
|
for i in range(n - 1): |
|
|
|
fcw(i) |
|
|
|
FCW() |
|
UCW() |
|
FCCW() |
|
|
|
perm() |
|
|
|
|
|
FCW() |
|
UCCW() |
|
FCCW() |
|
|
|
fccw(i) |
|
|
|
FCW() |
|
UCW() |
|
FCCW() |
|
assert perm(1) == I |
|
|
|
return g |
|
|