named_groups.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. from sympy.combinatorics.group_constructs import DirectProduct
  2. from sympy.combinatorics.perm_groups import PermutationGroup
  3. from sympy.combinatorics.permutations import Permutation
  4. _af_new = Permutation._af_new
  5. def AbelianGroup(*cyclic_orders):
  6. """
  7. Returns the direct product of cyclic groups with the given orders.
  8. Explanation
  9. ===========
  10. According to the structure theorem for finite abelian groups ([1]),
  11. every finite abelian group can be written as the direct product of
  12. finitely many cyclic groups.
  13. Examples
  14. ========
  15. >>> from sympy.combinatorics.named_groups import AbelianGroup
  16. >>> AbelianGroup(3, 4)
  17. PermutationGroup([
  18. (6)(0 1 2),
  19. (3 4 5 6)])
  20. >>> _.is_group
  21. True
  22. See Also
  23. ========
  24. DirectProduct
  25. References
  26. ==========
  27. .. [1] https://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely_generated_abelian_groups
  28. """
  29. groups = []
  30. degree = 0
  31. order = 1
  32. for size in cyclic_orders:
  33. degree += size
  34. order *= size
  35. groups.append(CyclicGroup(size))
  36. G = DirectProduct(*groups)
  37. G._is_abelian = True
  38. G._degree = degree
  39. G._order = order
  40. return G
  41. def AlternatingGroup(n):
  42. """
  43. Generates the alternating group on ``n`` elements as a permutation group.
  44. Explanation
  45. ===========
  46. For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for
  47. ``n`` odd
  48. and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.).
  49. After the group is generated, some of its basic properties are set.
  50. The cases ``n = 1, 2`` are handled separately.
  51. Examples
  52. ========
  53. >>> from sympy.combinatorics.named_groups import AlternatingGroup
  54. >>> G = AlternatingGroup(4)
  55. >>> G.is_group
  56. True
  57. >>> a = list(G.generate_dimino())
  58. >>> len(a)
  59. 12
  60. >>> all(perm.is_even for perm in a)
  61. True
  62. See Also
  63. ========
  64. SymmetricGroup, CyclicGroup, DihedralGroup
  65. References
  66. ==========
  67. .. [1] Armstrong, M. "Groups and Symmetry"
  68. """
  69. # small cases are special
  70. if n in (1, 2):
  71. return PermutationGroup([Permutation([0])])
  72. a = list(range(n))
  73. a[0], a[1], a[2] = a[1], a[2], a[0]
  74. gen1 = a
  75. if n % 2:
  76. a = list(range(1, n))
  77. a.append(0)
  78. gen2 = a
  79. else:
  80. a = list(range(2, n))
  81. a.append(1)
  82. a.insert(0, 0)
  83. gen2 = a
  84. gens = [gen1, gen2]
  85. if gen1 == gen2:
  86. gens = gens[:1]
  87. G = PermutationGroup([_af_new(a) for a in gens], dups=False)
  88. set_alternating_group_properties(G, n, n)
  89. G._is_alt = True
  90. return G
  91. def set_alternating_group_properties(G, n, degree):
  92. """Set known properties of an alternating group. """
  93. if n < 4:
  94. G._is_abelian = True
  95. G._is_nilpotent = True
  96. else:
  97. G._is_abelian = False
  98. G._is_nilpotent = False
  99. if n < 5:
  100. G._is_solvable = True
  101. else:
  102. G._is_solvable = False
  103. G._degree = degree
  104. G._is_transitive = True
  105. G._is_dihedral = False
  106. def CyclicGroup(n):
  107. """
  108. Generates the cyclic group of order ``n`` as a permutation group.
  109. Explanation
  110. ===========
  111. The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)``
  112. (in cycle notation). After the group is generated, some of its basic
  113. properties are set.
  114. Examples
  115. ========
  116. >>> from sympy.combinatorics.named_groups import CyclicGroup
  117. >>> G = CyclicGroup(6)
  118. >>> G.is_group
  119. True
  120. >>> G.order()
  121. 6
  122. >>> list(G.generate_schreier_sims(af=True))
  123. [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1],
  124. [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]]
  125. See Also
  126. ========
  127. SymmetricGroup, DihedralGroup, AlternatingGroup
  128. """
  129. a = list(range(1, n))
  130. a.append(0)
  131. gen = _af_new(a)
  132. G = PermutationGroup([gen])
  133. G._is_abelian = True
  134. G._is_nilpotent = True
  135. G._is_solvable = True
  136. G._degree = n
  137. G._is_transitive = True
  138. G._order = n
  139. G._is_dihedral = (n == 2)
  140. return G
  141. def DihedralGroup(n):
  142. r"""
  143. Generates the dihedral group `D_n` as a permutation group.
  144. Explanation
  145. ===========
  146. The dihedral group `D_n` is the group of symmetries of the regular
  147. ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)``
  148. (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...``
  149. (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that
  150. these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate
  151. `D_n` (See [1]). After the group is generated, some of its basic properties
  152. are set.
  153. Examples
  154. ========
  155. >>> from sympy.combinatorics.named_groups import DihedralGroup
  156. >>> G = DihedralGroup(5)
  157. >>> G.is_group
  158. True
  159. >>> a = list(G.generate_dimino())
  160. >>> [perm.cyclic_form for perm in a]
  161. [[], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]],
  162. [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[0, 4], [1, 3]],
  163. [[1, 4], [2, 3]], [[0, 1], [2, 4]], [[0, 2], [3, 4]],
  164. [[0, 3], [1, 2]]]
  165. See Also
  166. ========
  167. SymmetricGroup, CyclicGroup, AlternatingGroup
  168. References
  169. ==========
  170. .. [1] https://en.wikipedia.org/wiki/Dihedral_group
  171. """
  172. # small cases are special
  173. if n == 1:
  174. return PermutationGroup([Permutation([1, 0])])
  175. if n == 2:
  176. return PermutationGroup([Permutation([1, 0, 3, 2]),
  177. Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])])
  178. a = list(range(1, n))
  179. a.append(0)
  180. gen1 = _af_new(a)
  181. a = list(range(n))
  182. a.reverse()
  183. gen2 = _af_new(a)
  184. G = PermutationGroup([gen1, gen2])
  185. # if n is a power of 2, group is nilpotent
  186. if n & (n-1) == 0:
  187. G._is_nilpotent = True
  188. else:
  189. G._is_nilpotent = False
  190. G._is_dihedral = True
  191. G._is_abelian = False
  192. G._is_solvable = True
  193. G._degree = n
  194. G._is_transitive = True
  195. G._order = 2*n
  196. return G
  197. def SymmetricGroup(n):
  198. """
  199. Generates the symmetric group on ``n`` elements as a permutation group.
  200. Explanation
  201. ===========
  202. The generators taken are the ``n``-cycle
  203. ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation).
  204. (See [1]). After the group is generated, some of its basic properties
  205. are set.
  206. Examples
  207. ========
  208. >>> from sympy.combinatorics.named_groups import SymmetricGroup
  209. >>> G = SymmetricGroup(4)
  210. >>> G.is_group
  211. True
  212. >>> G.order()
  213. 24
  214. >>> list(G.generate_schreier_sims(af=True))
  215. [[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 1, 2, 0], [0, 2, 3, 1],
  216. [1, 3, 0, 2], [2, 0, 1, 3], [3, 2, 0, 1], [0, 3, 1, 2], [1, 0, 2, 3],
  217. [2, 1, 3, 0], [3, 0, 1, 2], [0, 1, 3, 2], [1, 2, 0, 3], [2, 3, 1, 0],
  218. [3, 1, 0, 2], [0, 2, 1, 3], [1, 3, 2, 0], [2, 0, 3, 1], [3, 2, 1, 0],
  219. [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3], [3, 0, 2, 1]]
  220. See Also
  221. ========
  222. CyclicGroup, DihedralGroup, AlternatingGroup
  223. References
  224. ==========
  225. .. [1] https://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations
  226. """
  227. if n == 1:
  228. G = PermutationGroup([Permutation([0])])
  229. elif n == 2:
  230. G = PermutationGroup([Permutation([1, 0])])
  231. else:
  232. a = list(range(1, n))
  233. a.append(0)
  234. gen1 = _af_new(a)
  235. a = list(range(n))
  236. a[0], a[1] = a[1], a[0]
  237. gen2 = _af_new(a)
  238. G = PermutationGroup([gen1, gen2])
  239. set_symmetric_group_properties(G, n, n)
  240. G._is_sym = True
  241. return G
  242. def set_symmetric_group_properties(G, n, degree):
  243. """Set known properties of a symmetric group. """
  244. if n < 3:
  245. G._is_abelian = True
  246. G._is_nilpotent = True
  247. else:
  248. G._is_abelian = False
  249. G._is_nilpotent = False
  250. if n < 5:
  251. G._is_solvable = True
  252. else:
  253. G._is_solvable = False
  254. G._degree = degree
  255. G._is_transitive = True
  256. G._is_dihedral = (n in [2, 3]) # cf Landau's func and Stirling's approx
  257. def RubikGroup(n):
  258. """Return a group of Rubik's cube generators
  259. >>> from sympy.combinatorics.named_groups import RubikGroup
  260. >>> RubikGroup(2).is_group
  261. True
  262. """
  263. from sympy.combinatorics.generators import rubik
  264. if n <= 1:
  265. raise ValueError("Invalid cube. n has to be greater than 1")
  266. return PermutationGroup(rubik(n))