Esempio n. 1
0
def SymmetricPresentation(n):
    r"""
    Build the Symmetric group of order `n!` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Symmetric group of order `n!`.

    OUTPUT:

    Symmetric group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: S4 = groups.presentation.Symmetric(4)
        sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4))
        True

    TESTS::

        sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order()
        1
        sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3))
        (2, True)
        sage: S5 = groups.presentation.Symmetric(5)
        sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5))
        True
        sage: groups.presentation.Symmetric(8).order()
        40320
    """
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = SymmetricGroup(n)
    GAP_fp_rep = libgap.Image(
        libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple([
        F(rel_word.TietzeWordAbstractWord(image_gens).sage())
        for rel_word in GAP_fp_rep.RelatorsOfFpGroup()
    ])
    return FinitelyPresentedGroup(F, ret_rls)
Esempio n. 2
0
def AlternatingPresentation(n):
    r"""
    Build the Alternating group of order `n!/2` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Alternating group of order `n!/2`.

    OUTPUT:

    Alternating group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: A6 = groups.presentation.Alternating(6)
        sage: A6.as_permutation_group().is_isomorphic(AlternatingGroup(6)), A6.order()
        (True, 360)

    TESTS::

        sage: #even permutation test..
        sage: A1 = groups.presentation.Alternating(1); A2 = groups.presentation.Alternating(2)
        sage: A1.is_isomorphic(A2), A1.order()
        (True, 1)
        sage: A3 = groups.presentation.Alternating(3); A3.order(), A3.as_permutation_group().is_cyclic()
        (3, True)
        sage: A8 = groups.presentation.Alternating(8); A8.order()
        20160
    """
    from sage.groups.perm_gps.permgroup_named import AlternatingGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = AlternatingGroup(n)
    GAP_fp_rep = libgap.Image(
        libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple([
        F(rel_word.TietzeWordAbstractWord(image_gens).sage())
        for rel_word in GAP_fp_rep.RelatorsOfFpGroup()
    ])
    return FinitelyPresentedGroup(F, ret_rls)
def SymmetricPresentation(n):
    r"""
    Build the Symmetric group of order `n!` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Symmetric group of order `n!`.

    OUTPUT:

    Symmetric group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: S4 = groups.presentation.Symmetric(4)
        sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4))
        True

    TESTS::

        sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order()
        1
        sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3))
        (2, True)
        sage: S5 = groups.presentation.Symmetric(5)
        sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5))
        True
        sage: groups.presentation.Symmetric(8).order()
        40320
    """
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = SymmetricGroup(n)
    GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple(
        [F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]
    )
    return FinitelyPresentedGroup(F, ret_rls)
def AlternatingPresentation(n):
    r"""
    Build the Alternating group of order `n!/2` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Alternating group of order `n!/2`.

    OUTPUT:

    Alternating group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: A6 = groups.presentation.Alternating(6)
        sage: A6.as_permutation_group().is_isomorphic(AlternatingGroup(6)), A6.order()
        (True, 360)

    TESTS::

        sage: #even permutation test..
        sage: A1 = groups.presentation.Alternating(1); A2 = groups.presentation.Alternating(2)
        sage: A1.is_isomorphic(A2), A1.order()
        (True, 1)
        sage: A3 = groups.presentation.Alternating(3); A3.order(), A3.as_permutation_group().is_cyclic()
        (3, True)
        sage: A8 = groups.presentation.Alternating(8); A8.order()
        20160
    """
    from sage.groups.perm_gps.permgroup_named import AlternatingGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = AlternatingGroup(n)
    GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple(
        [F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]
    )
    return FinitelyPresentedGroup(F, ret_rls)
Esempio n. 5
0
def FinitelyGeneratedAbelianPresentation(int_list):
    r"""
    Return canonical presentation of finitely generated abelian group.

    INPUT:

    - ``int_list`` -- List of integers defining the group to be returned, the defining list
      is reduced to the invariants of the input list before generating the corresponding
      group.

    OUTPUT:

    Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}`
    as a finite presentation, where `n_i` forms the invariants of the input list.

    EXAMPLES::

        sage: groups.presentation.FGAbelian([2,2])
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([2,3])
        Finitely presented group < a | a^6 >
        sage: groups.presentation.FGAbelian([2,4])
        Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b >

    You can create free abelian groups::

        sage: groups.presentation.FGAbelian([0])
        Finitely presented group < a |  >
        sage: groups.presentation.FGAbelian([0,0])
        Finitely presented group < a, b | a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,0,0])
        Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    And various infinite abelian groups::

        sage: groups.presentation.FGAbelian([0,2])
        Finitely presented group < a, b | a^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,2,2])
        Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    Outputs are reduced to minimal generators and relations::

        sage: groups.presentation.FGAbelian([3,5,2,7,3])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([3,210])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >

    The trivial group is an acceptable output::

        sage: groups.presentation.FGAbelian([])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1])
        Finitely presented group <  |  >

    Input list must consist of positive integers::

        sage: groups.presentation.FGAbelian([2,6,3,9,-4])
        Traceback (most recent call last):
        ...
        ValueError: input list must contain nonnegative entries
        sage: groups.presentation.FGAbelian([2,'a',4])
        Traceback (most recent call last):
        ...
        TypeError: unable to convert 'a' to an integer

    TESTS::

        sage: ag = groups.presentation.FGAbelian([2,2])
        sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour())
        True
        sage: G = groups.presentation.FGAbelian([2,4,8])
        sage: C2 = CyclicPermutationGroup(2)
        sage: C4 = CyclicPermutationGroup(4)
        sage: C8 = CyclicPermutationGroup(8)
        sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0]
        sage: gg.is_isomorphic(G.as_permutation_group())
        True
        sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35])
        True
    """
    from sage.groups.free_group import _lexi_gen
    check_ls = [Integer(x) for x in int_list if Integer(x) >= 0]
    if len(check_ls) != len(int_list):
        raise ValueError('input list must contain nonnegative entries')

    col_sp = diagonal_matrix(int_list).column_space()
    invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants()
    name_gen = _lexi_gen()
    F = FreeGroup([next(name_gen) for i in invariants])
    ret_rls = [
        F([i + 1])**invariants[i] for i in range(len(invariants))
        if invariants[i] != 0
    ]

    # Build commutator relations
    gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1)
                 for j in range(i + 1, F.ngens())]
    ret_rls = ret_rls + [
        x[0]**(-1) * x[1]**(-1) * x[0] * x[1] for x in gen_pairs
    ]
    return FinitelyPresentedGroup(F, tuple(ret_rls))
Esempio n. 6
0
def FinitelyGeneratedAbelianPresentation(int_list):
    r"""
    Return canonical presentation of finitely generated abelian group.

    INPUT:

    - ``int_list`` -- List of integers defining the group to be returned, the defining list
      is reduced to the invariants of the input list before generating the corresponding
      group.

    OUTPUT:

    Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}`
    as a finite presentation, where `n_i` forms the invariants of the input list.

    EXAMPLES::

        sage: groups.presentation.FGAbelian([2,2])
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([2,3])
        Finitely presented group < a | a^6 >
        sage: groups.presentation.FGAbelian([2,4])
        Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b >

    You can create free abelian groups::

        sage: groups.presentation.FGAbelian([0])
        Finitely presented group < a |  >
        sage: groups.presentation.FGAbelian([0,0])
        Finitely presented group < a, b | a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,0,0])
        Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    And various infinite abelian groups::

        sage: groups.presentation.FGAbelian([0,2])
        Finitely presented group < a, b | a^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,2,2])
        Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    Outputs are reduced to minimal generators and relations::

        sage: groups.presentation.FGAbelian([3,5,2,7,3])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([3,210])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >

    The trivial group is an acceptable output::

        sage: groups.presentation.FGAbelian([])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1])
        Finitely presented group <  |  >

    Input list must consist of positive integers::

        sage: groups.presentation.FGAbelian([2,6,3,9,-4])
        Traceback (most recent call last):
        ...
        ValueError: input list must contain nonnegative entries
        sage: groups.presentation.FGAbelian([2,'a',4])
        Traceback (most recent call last):
        ...
        TypeError: unable to convert 'a' to an integer

    TESTS::

        sage: ag = groups.presentation.FGAbelian([2,2])
        sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour())
        True
        sage: G = groups.presentation.FGAbelian([2,4,8])
        sage: C2 = CyclicPermutationGroup(2)
        sage: C4 = CyclicPermutationGroup(4)
        sage: C8 = CyclicPermutationGroup(8)
        sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0]
        sage: gg.is_isomorphic(G.as_permutation_group())
        True
        sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35])
        True
    """
    from sage.groups.free_group import _lexi_gen
    check_ls = [Integer(x) for x in int_list if Integer(x) >= 0]
    if len(check_ls) != len(int_list):
        raise ValueError('input list must contain nonnegative entries')

    col_sp = diagonal_matrix(int_list).column_space()
    invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants()
    name_gen = _lexi_gen()
    F = FreeGroup([next(name_gen) for i in invariants])
    ret_rls = [F([i+1])**invariants[i] for i in range(len(invariants)) if invariants[i]!=0]

    # Build commutator relations
    gen_pairs = [[F.gen(i),F.gen(j)] for i in range(F.ngens()-1) for j in range(i+1,F.ngens())]
    ret_rls = ret_rls + [x[0]**(-1)*x[1]**(-1)*x[0]*x[1] for x in gen_pairs]
    return FinitelyPresentedGroup(F, tuple(ret_rls))
Esempio n. 7
0
    def direct_product(self, H, reduced=False, new_names=True):
        r"""
        Return the direct product of ``self`` with finitely presented
        group ``H``.

        Calls GAP function ``DirectProduct``, which returns the direct
        product of a list of groups of any representation.

        From [JohnsonPG90]_ (pg 45, proposition 4): If `G`, `H` are groups
        presented by `\langle X \mid R \rangle` and `\langle Y \mid S \rangle`
        respectively, then their direct product has the presentation
        `\langle X, Y \mid R, S, [X, Y] \rangle` where `[X, Y]` denotes the
        set of commutators `\{ x^{-1} y^{-1} x y \mid x \in X, y \in Y \}`.

        INPUT:

        - ``H`` -- a finitely presented group

        - ``reduced`` -- (default: ``False``) boolean; if ``True``, then
          attempt to reduce the presentation of the product group

        - ``new_names`` -- (default: ``True``) boolean; If ``True``, then
          lexicographical variable names are assigned to the generators of
          the group to be returned. If ``False``, the group to be returned
          keeps the generator names of the two groups forming the direct
          product. Note that one cannot ask to reduce the output and ask
          to keep the old variable names, as they they may change meaning
          in the output group if its presentation is reduced.

        OUTPUT:

        The direct product of ``self`` with ``H`` as a finitely
        presented group.

        EXAMPLES::

            sage: G = FreeGroup()
            sage: C12 =  ( G / [G([1,1,1,1])] ).direct_product( G / [G([1,1,1])]); C12
            Finitely presented group < a, b | a^4, b^3, a^-1*b^-1*a*b >
            sage: C12.order(), C12.as_permutation_group().is_cyclic()
            (12, True)
            sage: klein = ( G / [G([1,1])] ).direct_product( G / [G([1,1])]); klein
            Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
            sage: klein.order(), klein.as_permutation_group().is_cyclic()
            (4, False)

        We can keep the variable names from ``self`` and ``H`` to examine how
        new relations are formed::

            sage: F = FreeGroup("a"); G = FreeGroup("g")
            sage: X = G / [G.0^12]; A = F / [F.0^6]
            sage: X.direct_product(A, new_names=False)
            Finitely presented group < g, a | g^12, a^6, g^-1*a^-1*g*a >
            sage: A.direct_product(X, new_names=False)
            Finitely presented group < a, g | a^6, g^12, a^-1*g^-1*a*g >

        Or we can attempt to reduce the output group presentation::

            sage: F = FreeGroup("a"); G = FreeGroup("g")
            sage: X = G / [G.0]; A = F / [F.0]
            sage: X.direct_product(A, new_names=True)
            Finitely presented group < a, b | a, b, a^-1*b^-1*a*b >
            sage: X.direct_product(A, reduced=True, new_names=True)
            Finitely presented group <  |  >

        But we cannot do both::

            sage: K = FreeGroup(['a','b'])
            sage: D = K / [K.0^5, K.1^8]
            sage: D.direct_product(D, reduced=True, new_names=False)
            Traceback (most recent call last):
            ...
            ValueError: cannot reduce output and keep old variable names

        TESTS::

            sage: G = FreeGroup()
            sage: Dp = (G / [G([1,1])]).direct_product( G / [G([1,1,1,1,1,1])] )
            sage: Dp.as_permutation_group().is_isomorphic(PermutationGroup(['(1,2)','(3,4,5,6,7,8)']))
            True
            sage: C7 = G / [G.0**7]; C6 =  G / [G.0**6]
            sage: C14 = G / [G.0**14]; C3 =  G / [G.0**3]
            sage: C7.direct_product(C6).is_isomorphic(C14.direct_product(C3))
            True
            sage: F = FreeGroup(2); D = F / [F([1,1,1,1,1]),F([2,2]),F([1,2])**2]
            sage: D.direct_product(D).as_permutation_group().is_isomorphic(
            ....: direct_product_permgroups([DihedralGroup(5),DihedralGroup(5)]))
            True

        AUTHORS:

        - Davis Shurbert (2013-07-20): initial version

        REFERENCES:

        .. [JohnsonPG90] D.L. Johnson. *Presentations of Groups*.
           Cambridge University Press. (1990).
        """
        from sage.groups.free_group import FreeGroup, _lexi_gen

        if not isinstance(H, FinitelyPresentedGroup):
            raise TypeError("input must be a finitely presented group")
        if reduced and not new_names:
            raise ValueError(
                "cannot reduce output and keep old variable names")

        fp_product = libgap.DirectProduct([self.gap(), H.gap()])
        GAP_gens = fp_product.FreeGeneratorsOfFpGroup()
        if new_names:
            name_itr = _lexi_gen(
            )  # Python generator for lexicographical variable names
            gen_names = [name_itr.next() for i in GAP_gens]
        else:
            gen_names = [str(g)
                         for g in self.gens()] + [str(g) for g in H.gens()]
        # Build the direct product in Sage for better variable names
        ret_F = FreeGroup(gen_names)
        ret_rls = tuple([
            ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage())
            for rel_word in fp_product.RelatorsOfFpGroup()
        ])
        ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls)
        if reduced:
            ret_fpg = ret_fpg.simplified()
        return ret_fpg
Esempio n. 8
0
    def direct_product(self, H, reduced=False, new_names=True):
        r"""
        Return the direct product of ``self`` with finitely presented
        group ``H``.

        Calls GAP function ``DirectProduct``, which returns the direct
        product of a list of groups of any representation.

        From [JohnsonPG90]_ (pg 45, proposition 4): If `G`, `H` are groups
        presented by `\langle X \mid R \rangle` and `\langle Y \mid S \rangle`
        respectively, then their direct product has the presentation
        `\langle X, Y \mid R, S, [X, Y] \rangle` where `[X, Y]` denotes the
        set of commutators `\{ x^{-1} y^{-1} x y \mid x \in X, y \in Y \}`.

        INPUT:

        - ``H`` -- a finitely presented group

        - ``reduced`` -- (default: ``False``) boolean; if ``True``, then
          attempt to reduce the presentation of the product group

        - ``new_names`` -- (default: ``True``) boolean; If ``True``, then
          lexicographical variable names are assigned to the generators of
          the group to be returned. If ``False``, the group to be returned
          keeps the generator names of the two groups forming the direct
          product. Note that one cannot ask to reduce the output and ask
          to keep the old variable names, as they they may change meaning
          in the output group if its presentation is reduced.

        OUTPUT:

        The direct product of ``self`` with ``H`` as a finitely
        presented group.

        EXAMPLES::

            sage: G = FreeGroup()
            sage: C12 =  ( G / [G([1,1,1,1])] ).direct_product( G / [G([1,1,1])]); C12
            Finitely presented group < a, b | a^4, b^3, a^-1*b^-1*a*b >
            sage: C12.order(), C12.as_permutation_group().is_cyclic()
            (12, True)
            sage: klein = ( G / [G([1,1])] ).direct_product( G / [G([1,1])]); klein
            Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
            sage: klein.order(), klein.as_permutation_group().is_cyclic()
            (4, False)

        We can keep the variable names from ``self`` and ``H`` to examine how
        new relations are formed::

            sage: F = FreeGroup("a"); G = FreeGroup("g")
            sage: X = G / [G.0^12]; A = F / [F.0^6]
            sage: X.direct_product(A, new_names=False)
            Finitely presented group < g, a | g^12, a^6, g^-1*a^-1*g*a >
            sage: A.direct_product(X, new_names=False)
            Finitely presented group < a, g | a^6, g^12, a^-1*g^-1*a*g >

        Or we can attempt to reduce the output group presentation::

            sage: F = FreeGroup("a"); G = FreeGroup("g")
            sage: X = G / [G.0]; A = F / [F.0]
            sage: X.direct_product(A, new_names=True)
            Finitely presented group < a, b | a, b, a^-1*b^-1*a*b >
            sage: X.direct_product(A, reduced=True, new_names=True)
            Finitely presented group <  |  >

        But we cannot do both::

            sage: K = FreeGroup(['a','b'])
            sage: D = K / [K.0^5, K.1^8]
            sage: D.direct_product(D, reduced=True, new_names=False)
            Traceback (most recent call last):
            ...
            ValueError: cannot reduce output and keep old variable names

        TESTS::

            sage: G = FreeGroup()
            sage: Dp = (G / [G([1,1])]).direct_product( G / [G([1,1,1,1,1,1])] )
            sage: Dp.as_permutation_group().is_isomorphic(PermutationGroup(['(1,2)','(3,4,5,6,7,8)']))
            True
            sage: C7 = G / [G.0**7]; C6 =  G / [G.0**6]
            sage: C14 = G / [G.0**14]; C3 =  G / [G.0**3]
            sage: C7.direct_product(C6).is_isomorphic(C14.direct_product(C3))
            True
            sage: F = FreeGroup(2); D = F / [F([1,1,1,1,1]),F([2,2]),F([1,2])**2]
            sage: D.direct_product(D).as_permutation_group().is_isomorphic(
            ....: direct_product_permgroups([DihedralGroup(5),DihedralGroup(5)]))
            True

        AUTHORS:

        - Davis Shurbert (2013-07-20): initial version

        REFERENCES:

        .. [JohnsonPG90] D.L. Johnson. *Presentations of Groups*.
           Cambridge University Press. (1990).
        """
        from sage.groups.free_group import FreeGroup, _lexi_gen

        if not isinstance(H, FinitelyPresentedGroup):
            raise TypeError("input must be a finitely presented group")
        if reduced and not new_names:
            raise ValueError("cannot reduce output and keep old variable names")

        fp_product = libgap.DirectProduct([self.gap(), H.gap()])
        GAP_gens = fp_product.FreeGeneratorsOfFpGroup()
        if new_names:
            name_itr = _lexi_gen() # Python generator for lexicographical variable names
            gen_names = [name_itr.next() for i in GAP_gens]
        else:
            gen_names= [str(g) for g in self.gens()] + [str(g) for g in H.gens()]
        # Build the direct product in Sage for better variable names
        ret_F = FreeGroup(gen_names)
        ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage())
            for rel_word in fp_product.RelatorsOfFpGroup()])
        ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls)
        if reduced:
            ret_fpg = ret_fpg.simplified()
        return ret_fpg
Esempio n. 9
0
    def semidirect_product(self, H, hom, check=True, reduced=False):
        """
        The semidirect product of ``self`` with ``H`` via ``hom``.

        If there exists a homomorphism `\phi` from a group `G` to the
        automorphism group of a group `H`, then we can define the semidirect
        product of `G` with `H` via `\phi` as the cartesian product of `G`
        and `H` with the operation

        .. MATH::

                (g_1, h_1)(g_2, h_2) = (g_1 g_2, \phi(g_2)(h_1) h_2).

        INPUT:

        - ``H`` -- Finitely presented group which is implicitly acted on
          by ``self`` and can be naturally embedded as a normal subgroup
          of the semidirect product.

        - ``hom`` -- Homomorphism from ``self`` to the automorphism group
          of ``H``. Given as a pair, with generators of ``self`` in the
          first slot and the images of the corresponding generators in the
          second. These images must be automorphisms of ``H``, given again
          as a pair of generators and images.

        - ``check`` -- Boolean (default ``True``). If ``False`` the defining
          homomorphism and automorphism images are not tested for validity.
          This test can be costly with large groups, so it can be bypassed
          if the user is confident that his morphisms are valid.

        - ``reduced`` -- Boolean (default ``False``). If ``True`` then the
          method attempts to reduce the presentation of the output group.

        OUTPUT:

        The semidirect product of ``self`` with ``H`` via ``hom`` as a
        finitely presented group. See
        :meth:`PermutationGroup_generic.semidirect_product
        <sage.groups.perm_gps.permgroup.PermutationGroup_generic.semidirect_product>`
        for a more in depth explanation of a semidirect product.

        AUTHORS:

        - Davis Shurbert (8-1-2013)

        EXAMPLES:

        Group of order 12 as two isomorphic semidirect products::

            sage: D4 = groups.presentation.Dihedral(4)
            sage: C3 = groups.presentation.Cyclic(3)
            sage: alpha1 = ([C3.gen(0)],[C3.gen(0)])
            sage: alpha2 = ([C3.gen(0)],[C3([1,1])])
            sage: S1 = D4.semidirect_product(C3, ([D4.gen(1), D4.gen(0)],[alpha1,alpha2]))
            sage: C2 = groups.presentation.Cyclic(2)
            sage: Q = groups.presentation.DiCyclic(3)
            sage: a = Q([1]); b = Q([-2])
            sage: alpha = (Q.gens(), [a,b])
            sage: S2 = C2.semidirect_product(Q, ([C2.0],[alpha]))
            sage: S1.is_isomorphic(S2)
            True

        Dihedral groups can be constructed as semidirect products
        of cyclic groups::

            sage: C2 = groups.presentation.Cyclic(2)
            sage: C8 = groups.presentation.Cyclic(8)
            sage: hom = (C2.gens(), [ ([C8([1])], [C8([-1])]) ])
            sage: D = C2.semidirect_product(C8, hom)
            sage: D.as_permutation_group().is_isomorphic(DihedralGroup(8))
            True

        You can attempt to reduce the presentation of the output group::

            sage: D = C2.semidirect_product(C8, hom); D
            Finitely presented group < a, b, c, d |
             a^2, b^-1*a^-1*b*a*d^-1*c^-1, c^-1*a^-1*c*a*d^-1, d^-1*a^-1*d*a,
             b^2*c^-1, c^-1*b^-1*c*b, d^-1*b^-1*d*b, c^2*d^-1, d^-1*c^-1*d*c, d^2 >
            sage: D = C2.semidirect_product(C8, hom, reduced=True); D
            Finitely presented group < a, b | a^2, (a*b)^2, b^8 >

            sage: C3 = groups.presentation.Cyclic(3)
            sage: C4 = groups.presentation.Cyclic(4)
            sage: hom = (C3.gens(), [(C4.gens(), C4.gens())])
            sage: C3.semidirect_product(C4, hom)
            Finitely presented group < a, b, c |
             a^3, b^-1*a^-1*b*a, c^-1*a^-1*c*a, b^2*c^-1, c^-1*b^-1*c*b, c^2 >
            sage: D = C3.semidirect_product(C4, hom, reduced=True); D
            Finitely presented group < a, b | a^3, b^4, b^-1*a^-1*b*a >
            sage: D.as_permutation_group().is_cyclic()
            True

        You can turn off the checks for the validity of the input morphisms.
        This check is expensive but behavior is unpredictable if inputs are
        invalid and are not caught by these tests::

            sage: C5 = groups.presentation.Cyclic(5)
            sage: C12 = groups.presentation.Cyclic(12)
            sage: hom = (C5.gens(), [(C12.gens(), C12.gens())])
            sage: sp = C5.semidirect_product(C12, hom, check=False); sp
            Finitely presented group < a, b, c, d |
             a^5, b^-1*a^-1*b*a, c^-1*a^-1*c*a, d^-1*a^-1*d*a, b^2*d^-1,
             c^-1*b^-1*c*b, d^-1*b^-1*d*b, c^3, d^-1*c^-1*d*c, d^2 >
            sage: sp.as_permutation_group().is_cyclic(), sp.order()
            (True, 60)

        TESTS:

        The following was fixed in Gap-4.7.2::

            sage: C5.semidirect_product(C12, hom) == sp
            True

        A more complicated semidirect product::

            sage: C = groups.presentation.Cyclic(7)
            sage: D = groups.presentation.Dihedral(5)
            sage: id1 = ([C.0], [(D.gens(),D.gens())])
            sage: Se1 =  C.semidirect_product(D, id1)
            sage: id2 = (D.gens(), [(C.gens(),C.gens()),(C.gens(),C.gens())])
            sage: Se2 =  D.semidirect_product(C ,id2)
            sage: Dp1 = C.direct_product(D);
            sage: Dp1.is_isomorphic(Se1), Dp1.is_isomorphic(Se2)
            (True, True)

        Most checks for validity of input are left to GAP to handle::

            sage: bad_aut = ([C.0], [(D.gens(),[D.0, D.0])])
            sage: C.semidirect_product(D, bad_aut)
            Traceback (most recent call last):
            ...
            ValueError: images of input homomorphism must be automorphisms
            sage: bad_hom = ([D.0, D.1], [(C.gens(),C.gens())])
            sage: D.semidirect_product(C, bad_hom)
            Traceback (most recent call last):
            ...
            ValueError: libGAP: Error, <gens> and <imgs> must be lists of same length
        """
        from sage.groups.free_group import FreeGroup, _lexi_gen

        if not isinstance(H, FinitelyPresentedGroup):
            raise TypeError("input must be a finitely presented group")

        GAP_self = self.gap(); GAP_H = H.gap()
        auto_grp = libgap.AutomorphismGroup(H.gap())
        self_gens = [h.gap() for h in hom[0]]
        # construct image automorphisms in GAP
        GAP_aut_imgs = [ libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns],
            [i.gap() for i in img]) for (gns, img) in hom[1] ]

        # check for automorphism validity in images of operation defining homomorphism,
        # and construct the defining homomorphism.
        if check:
            if not all([a in libgap.List(libgap.AutomorphismGroup(GAP_H)) for a in GAP_aut_imgs]):
                raise ValueError("images of input homomorphism must be automorphisms")
            GAP_def_hom = libgap.GroupHomomorphismByImages(GAP_self, auto_grp, self_gens, GAP_aut_imgs)
        else:
            GAP_def_hom = GAP_self.GroupHomomorphismByImagesNC( auto_grp, self_gens, GAP_aut_imgs)

        prod = libgap.SemidirectProduct(GAP_self, GAP_def_hom, GAP_H)
        # Convert pc group to fp group
        if prod.IsPcGroup():
            prod = libgap.Image(libgap.IsomorphismFpGroupByPcgs(prod.FamilyPcgs() , 'x'))
        if not prod.IsFpGroup():
            raise NotImplementedError("unable to convert GAP output to equivalent Sage fp group")

        # Convert GAP group object to Sage via Tietze
        # lists for readability of variable names
        GAP_gens = prod.FreeGeneratorsOfFpGroup()
        name_itr = _lexi_gen() # Python generator for lexicographical variable names
        ret_F = FreeGroup([name_itr.next() for i in GAP_gens])
        ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage())
            for rel_word in prod.RelatorsOfFpGroup()])
        ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls)
        if reduced:
            ret_fpg = ret_fpg.simplified()
        return ret_fpg