text: from __future__ import print_function, division
  
  from sympy.combinatorics.permutations import Permutation
  from sympy.utilities.iterables import variations, rotate_left
  from sympy.core.symbol import symbols
  from sympy.matrices import Matrix
  from sympy.core.compatibility import range
  
  
  def symmetric(n):
      """
      Generates the symmetric group of order n, Sn.
  
      Examples
      ========
  
      >>> from sympy.combinatorics.permutations import Permutation
      >>> Permutation.print_cyclic = True
      >>> 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(list(range(n)), n):
          yield Permutation(perm)
  
  
  def cyclic(n):
      """
      Generates the cyclic group of order n, Cn.
  
      Examples
      ========
  
      >>> from sympy.combinatorics.permutations import Permutation
      >>> Permutation.print_cyclic = True
      >>> 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.permutations import Permutation
      >>> Permutation.print_cyclic = True
      >>> from sympy.combinatorics.generators import alternating
      >>> list(alternating(3))
      [(2), (0 1 2), (0 2 1)]
      """
      for perm in variations(list(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.permutations import Permutation
      >>> Permutation.print_cyclic = True
      >>> 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
      http://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
  