123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- from sympy.combinatorics.group_constructs import DirectProduct
- from sympy.combinatorics.perm_groups import PermutationGroup
- from sympy.combinatorics.permutations import Permutation
- _af_new = Permutation._af_new
- def AbelianGroup(*cyclic_orders):
- """
- Returns the direct product of cyclic groups with the given orders.
- Explanation
- ===========
- According to the structure theorem for finite abelian groups ([1]),
- every finite abelian group can be written as the direct product of
- finitely many cyclic groups.
- Examples
- ========
- >>> from sympy.combinatorics.named_groups import AbelianGroup
- >>> AbelianGroup(3, 4)
- PermutationGroup([
- (6)(0 1 2),
- (3 4 5 6)])
- >>> _.is_group
- True
- See Also
- ========
- DirectProduct
- References
- ==========
- .. [1] https://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely_generated_abelian_groups
- """
- groups = []
- degree = 0
- order = 1
- for size in cyclic_orders:
- degree += size
- order *= size
- groups.append(CyclicGroup(size))
- G = DirectProduct(*groups)
- G._is_abelian = True
- G._degree = degree
- G._order = order
- return G
- def AlternatingGroup(n):
- """
- Generates the alternating group on ``n`` elements as a permutation group.
- Explanation
- ===========
- For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for
- ``n`` odd
- and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.).
- After the group is generated, some of its basic properties are set.
- The cases ``n = 1, 2`` are handled separately.
- Examples
- ========
- >>> from sympy.combinatorics.named_groups import AlternatingGroup
- >>> G = AlternatingGroup(4)
- >>> G.is_group
- True
- >>> a = list(G.generate_dimino())
- >>> len(a)
- 12
- >>> all(perm.is_even for perm in a)
- True
- See Also
- ========
- SymmetricGroup, CyclicGroup, DihedralGroup
- References
- ==========
- .. [1] Armstrong, M. "Groups and Symmetry"
- """
- # small cases are special
- if n in (1, 2):
- return PermutationGroup([Permutation([0])])
- a = list(range(n))
- a[0], a[1], a[2] = a[1], a[2], a[0]
- gen1 = a
- if n % 2:
- a = list(range(1, n))
- a.append(0)
- gen2 = a
- else:
- a = list(range(2, n))
- a.append(1)
- a.insert(0, 0)
- gen2 = a
- gens = [gen1, gen2]
- if gen1 == gen2:
- gens = gens[:1]
- G = PermutationGroup([_af_new(a) for a in gens], dups=False)
- set_alternating_group_properties(G, n, n)
- G._is_alt = True
- return G
- def set_alternating_group_properties(G, n, degree):
- """Set known properties of an alternating group. """
- if n < 4:
- G._is_abelian = True
- G._is_nilpotent = True
- else:
- G._is_abelian = False
- G._is_nilpotent = False
- if n < 5:
- G._is_solvable = True
- else:
- G._is_solvable = False
- G._degree = degree
- G._is_transitive = True
- G._is_dihedral = False
- def CyclicGroup(n):
- """
- Generates the cyclic group of order ``n`` as a permutation group.
- Explanation
- ===========
- The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)``
- (in cycle notation). After the group is generated, some of its basic
- properties are set.
- Examples
- ========
- >>> from sympy.combinatorics.named_groups import CyclicGroup
- >>> G = CyclicGroup(6)
- >>> G.is_group
- True
- >>> G.order()
- 6
- >>> list(G.generate_schreier_sims(af=True))
- [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1],
- [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]]
- See Also
- ========
- SymmetricGroup, DihedralGroup, AlternatingGroup
- """
- a = list(range(1, n))
- a.append(0)
- gen = _af_new(a)
- G = PermutationGroup([gen])
- G._is_abelian = True
- G._is_nilpotent = True
- G._is_solvable = True
- G._degree = n
- G._is_transitive = True
- G._order = n
- G._is_dihedral = (n == 2)
- return G
- def DihedralGroup(n):
- r"""
- Generates the dihedral group `D_n` as a permutation group.
- Explanation
- ===========
- The dihedral group `D_n` is the group of symmetries of the regular
- ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)``
- (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...``
- (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that
- these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate
- `D_n` (See [1]). After the group is generated, some of its basic properties
- are set.
- Examples
- ========
- >>> from sympy.combinatorics.named_groups import DihedralGroup
- >>> G = DihedralGroup(5)
- >>> G.is_group
- True
- >>> a = list(G.generate_dimino())
- >>> [perm.cyclic_form for perm in a]
- [[], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]],
- [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[0, 4], [1, 3]],
- [[1, 4], [2, 3]], [[0, 1], [2, 4]], [[0, 2], [3, 4]],
- [[0, 3], [1, 2]]]
- See Also
- ========
- SymmetricGroup, CyclicGroup, AlternatingGroup
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Dihedral_group
- """
- # small cases are special
- if n == 1:
- return PermutationGroup([Permutation([1, 0])])
- if n == 2:
- return PermutationGroup([Permutation([1, 0, 3, 2]),
- Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])])
- a = list(range(1, n))
- a.append(0)
- gen1 = _af_new(a)
- a = list(range(n))
- a.reverse()
- gen2 = _af_new(a)
- G = PermutationGroup([gen1, gen2])
- # if n is a power of 2, group is nilpotent
- if n & (n-1) == 0:
- G._is_nilpotent = True
- else:
- G._is_nilpotent = False
- G._is_dihedral = True
- G._is_abelian = False
- G._is_solvable = True
- G._degree = n
- G._is_transitive = True
- G._order = 2*n
- return G
- def SymmetricGroup(n):
- """
- Generates the symmetric group on ``n`` elements as a permutation group.
- Explanation
- ===========
- The generators taken are the ``n``-cycle
- ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation).
- (See [1]). After the group is generated, some of its basic properties
- are set.
- Examples
- ========
- >>> from sympy.combinatorics.named_groups import SymmetricGroup
- >>> G = SymmetricGroup(4)
- >>> G.is_group
- True
- >>> G.order()
- 24
- >>> list(G.generate_schreier_sims(af=True))
- [[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 1, 2, 0], [0, 2, 3, 1],
- [1, 3, 0, 2], [2, 0, 1, 3], [3, 2, 0, 1], [0, 3, 1, 2], [1, 0, 2, 3],
- [2, 1, 3, 0], [3, 0, 1, 2], [0, 1, 3, 2], [1, 2, 0, 3], [2, 3, 1, 0],
- [3, 1, 0, 2], [0, 2, 1, 3], [1, 3, 2, 0], [2, 0, 3, 1], [3, 2, 1, 0],
- [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3], [3, 0, 2, 1]]
- See Also
- ========
- CyclicGroup, DihedralGroup, AlternatingGroup
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations
- """
- if n == 1:
- G = PermutationGroup([Permutation([0])])
- elif n == 2:
- G = PermutationGroup([Permutation([1, 0])])
- else:
- a = list(range(1, n))
- a.append(0)
- gen1 = _af_new(a)
- a = list(range(n))
- a[0], a[1] = a[1], a[0]
- gen2 = _af_new(a)
- G = PermutationGroup([gen1, gen2])
- set_symmetric_group_properties(G, n, n)
- G._is_sym = True
- return G
- def set_symmetric_group_properties(G, n, degree):
- """Set known properties of a symmetric group. """
- if n < 3:
- G._is_abelian = True
- G._is_nilpotent = True
- else:
- G._is_abelian = False
- G._is_nilpotent = False
- if n < 5:
- G._is_solvable = True
- else:
- G._is_solvable = False
- G._degree = degree
- G._is_transitive = True
- G._is_dihedral = (n in [2, 3]) # cf Landau's func and Stirling's approx
- def RubikGroup(n):
- """Return a group of Rubik's cube generators
- >>> from sympy.combinatorics.named_groups import RubikGroup
- >>> RubikGroup(2).is_group
- True
- """
- from sympy.combinatorics.generators import rubik
- if n <= 1:
- raise ValueError("Invalid cube. n has to be greater than 1")
- return PermutationGroup(rubik(n))
|