def BinaryDihedralPresentation(n):
    r"""
    Build a binary dihedral group of order `4n` as a finitely presented group.

    The binary dihedral group `BD_n` has the following presentation
    (note that there is a typo in [Sun]_):

    .. MATH::

        BD_n = \langle x, y, z | x^2 = y^2 = z^n = x y z \rangle.

    INPUT:

    - ``n`` -- the value `n`

    OUTPUT:

    The binary dihedral group of order `4n` as finite presentation.

    EXAMPLES::

        sage: groups.presentation.BinaryDihedral(9)
        Finitely presented group < x, y, z | x^-2*y^2, x^-2*z^9, x^-1*y*z >

    TESTS::

        sage: for n in range(3, 9):
        ....:     P = groups.presentation.BinaryDihedral(n)
        ....:     M = groups.matrix.BinaryDihedral(n)
        ....:     assert P.is_isomorphic(M)
    """
    F = FreeGroup('x,y,z')
    x,y,z = F.gens()
    rls = (x**-2 * y**2, x**-2 * z**n, x**-2 * x*y*z)
    return FinitelyPresentedGroup(F, rls)
示例#2
0
    def __init__(self, names):
        """
        Python constructor.

        INPUT:

        - ``names`` -- a tuple of strings. The names of the
          generators.

        TESTS::

            sage: B1 = BraidGroup(5) # indirect doctest
            sage: B1
            Braid group on 5 strands

        Check that :trac:`14081` is fixed::

            sage: BraidGroup(2)
            Braid group on 2 strands
            sage: BraidGroup(('a',))
            Braid group on 2 strands
        """
        n = len(names)
        if n < 1:  #n is the number of generators, not the number of strands (see ticket 14081)
            raise ValueError(
                "the number of strands must be an integer bigger than one")
        free_group = FreeGroup(names)
        rels = []
        for i in range(1, n):
            if i < n - 1:
                rels.append(free_group([i, i + 1, i, -i - 1, -i, -i - 1]))
            for j in range(i + 2, n):
                rels.append(free_group([i, j, -i, -j]))
        FinitelyPresentedGroup.__init__(self, free_group, tuple(rels))
        self._nstrands_ = n + 1
示例#3
0
def CyclicPresentation(n):
    r"""
    Build cyclic group of order `n` as a finitely presented group.

    INPUT:

    - ``n`` -- The order of the cyclic presentation to be returned.

    OUTPUT:

    The cyclic group of order `n` as finite presentation.

    EXAMPLES::

        sage: groups.presentation.Cyclic(10)
        Finitely presented group < a | a^10 >
        sage: n = 8; C = groups.presentation.Cyclic(n)
        sage: C.as_permutation_group().is_isomorphic(CyclicPermutationGroup(n))
        True

    TESTS::

        sage: groups.presentation.Cyclic(0)
        Traceback (most recent call last):
        ...
        ValueError: finitely presented group order must be positive
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('finitely presented group order must be positive')
    F = FreeGroup( 'a' )
    rls = F([1])**n,
    return FinitelyPresentedGroup( F, rls )
示例#4
0
def QuaternionPresentation():
    r"""
    Build the Quaternion group of order 8 as a finitely presented group.

    OUTPUT:

    Quaternion group as a finite presentation.

    EXAMPLES::

        sage: Q = groups.presentation.Quaternion(); Q
        Finitely presented group < a, b | a^4, b^2*a^-2, a*b*a*b^-1 >
        sage: Q.as_permutation_group().is_isomorphic(QuaternionGroup())
        True

    TESTS::

        sage: Q = groups.presentation.Quaternion()
        sage: Q.order(), Q.is_abelian()
        (8, False)
        sage: Q.is_isomorphic(groups.presentation.DiCyclic(2))
        True
    """
    F = FreeGroup(['a','b'])
    rls = F([1])**4, F([2,2,-1,-1]), F([1,2,1,-2])
    return FinitelyPresentedGroup(F, rls)
示例#5
0
    def __init__(self, coxeter_matrix, names):
        """
        Initialize ``self``.

        TESTS::

            sage: A = ArtinGroup(['D',4])
            sage: TestSuite(A).run()
            sage: A = ArtinGroup(['B',3], ['x','y','z'])
            sage: TestSuite(A).run()
        """
        self._coxeter_group = CoxeterGroup(coxeter_matrix)
        free_group = FreeGroup(names)
        rels = []
        # Generate the relations based on the Coxeter graph
        I = coxeter_matrix.index_set()
        for ii, i in enumerate(I):
            for j in I[ii + 1:]:
                m = coxeter_matrix[i, j]
                if m == Infinity:  # no relation
                    continue
                elt = [i, j] * m
                for ind in range(m, 2 * m):
                    elt[ind] = -elt[ind]
                rels.append(free_group(elt))
        FinitelyPresentedGroup.__init__(self, free_group, tuple(rels))
示例#6
0
    def __init__(self, G, names):
        """
        Initialize ``self``.

        TESTS::

            sage: G = RightAngledArtinGroup(graphs.CycleGraph(5))
            sage: TestSuite(G).run()
        """
        self._graph = G
        F = FreeGroup(names=names)
        CG = Graph(G).complement()  # Make sure it's mutable
        CG.relabel()  # Standardize the labels
        cm = [[-1] * CG.num_verts() for _ in range(CG.num_verts())]
        for i in range(CG.num_verts()):
            cm[i][i] = 1
        for u, v in CG.edge_iterator(labels=False):
            cm[u][v] = 2
            cm[v][u] = 2
        self._coxeter_group = CoxeterGroup(
            CoxeterMatrix(cm, index_set=G.vertices()))
        rels = tuple(
            F([i + 1, j + 1, -i - 1, -j - 1])
            for i, j in CG.edge_iterator(labels=False))  # +/- 1 for indexing
        FinitelyPresentedGroup.__init__(self, F, rels)
示例#7
0
    def __init__(self, names):
        """
        Python constructor.

        INPUT:

        - ``names`` -- a tuple of strings. The names of the
          generators.

        TESTS::

            sage: B1 = BraidGroup(5) # indirect doctest
            sage: B1
            Braid group on 5 strands
            sage: TestSuite(B1).run()


        Check that :trac:`14081` is fixed::

            sage: BraidGroup(2)
            Braid group on 2 strands
            sage: BraidGroup(('a',))
            Braid group on 2 strands

        Check that :trac:`15505` is fixed::

            sage: B=BraidGroup(4)
            sage: B.relations()
            (s0*s1*s0*s1^-1*s0^-1*s1^-1, s0*s2*s0^-1*s2^-1, s1*s2*s1*s2^-1*s1^-1*s2^-1)
            sage: B=BraidGroup('a,b,c,d,e,f')
            sage: B.relations()
            (a*b*a*b^-1*a^-1*b^-1,
             a*c*a^-1*c^-1,
             a*d*a^-1*d^-1,
             a*e*a^-1*e^-1,
             a*f*a^-1*f^-1,
             b*c*b*c^-1*b^-1*c^-1,
             b*d*b^-1*d^-1,
             b*e*b^-1*e^-1,
             b*f*b^-1*f^-1,
             c*d*c*d^-1*c^-1*d^-1,
             c*e*c^-1*e^-1,
             c*f*c^-1*f^-1,
             d*e*d*e^-1*d^-1*e^-1,
             d*f*d^-1*f^-1,
             e*f*e*f^-1*e^-1*f^-1)
        """
        n = len(names)
        if n < 1:  #n is the number of generators, not the number of strands (see ticket 14081)
            raise ValueError(
                "the number of strands must be an integer bigger than one")
        free_group = FreeGroup(names)
        rels = []
        for i in range(1, n):
            rels.append(free_group([i, i + 1, i, -i - 1, -i, -i - 1]))
            for j in range(i + 2, n + 1):
                rels.append(free_group([i, j, -i, -j]))
        FinitelyPresentedGroup.__init__(self, free_group, tuple(rels))
        self._nstrands_ = n + 1
示例#8
0
def BinaryDihedralPresentation(n):
    r"""
    Build a binary dihedral group of order `4n` as a finitely presented group.

    The binary dihedral group `BD_n` has the following presentation
    (note that there is a typo in [Sun]_):

    .. MATH::

        BD_n = \langle x, y, z | x^2 = y^2 = z^n = x y z \rangle.

    INPUT:

    - ``n`` -- the value `n`

    OUTPUT:

    The binary dihedral group of order `4n` as finite presentation.

    EXAMPLES::

        sage: groups.presentation.BinaryDihedral(9)
        Finitely presented group < x, y, z | x^-2*y^2, x^-2*z^9, x^-1*y*z >

    TESTS::

        sage: for n in range(3, 9):
        ....:     P = groups.presentation.BinaryDihedral(n)
        ....:     M = groups.matrix.BinaryDihedral(n)
        ....:     assert P.is_isomorphic(M)
        #I  Forcing finiteness test
        #I  Forcing finiteness test
        #I  Forcing finiteness test
        #I  Forcing finiteness test
        #I  Forcing finiteness test
        #I  Forcing finiteness test
    """
    F = FreeGroup('x,y,z')
    x, y, z = F.gens()
    rls = (x**-2 * y**2, x**-2 * z**n, x**-2 * x * y * z)
    return FinitelyPresentedGroup(F, rls)
示例#9
0
def DiCyclicPresentation(n):
    r"""
    Build the dicyclic group of order `4n`, for `n \geq 2`, as a finitely
    presented group.

    INPUT:

    - ``n`` -- positive integer, 2 or greater, determining the order of
      the group (`4n`).

    OUTPUT:

    The dicyclic group of order `4n` is defined by the presentation

    .. MATH::

        \langle a, x \mid a^{2n}=1, x^{2}=a^{n}, x^{-1}ax=a^{-1} \rangle

    .. NOTE::

        This group is also available as a permutation group via
        :class:`groups.permutation.DiCyclic <sage.groups.perm_gps.permgroup_named.DiCyclicGroup>`.

    EXAMPLES::

        sage: D = groups.presentation.DiCyclic(9); D
        Finitely presented group < a, b | a^18, b^2*a^-9, b^-1*a*b*a >
        sage: D.as_permutation_group().is_isomorphic(groups.permutation.DiCyclic(9))
        True

    TESTS::

        sage: Q = groups.presentation.DiCyclic(2)
        sage: Q.as_permutation_group().is_isomorphic(QuaternionGroup())
        True
        sage: for i in [5, 8, 12, 32]:
        ....:     A = groups.presentation.DiCyclic(i).as_permutation_group()
        ....:     B = groups.permutation.DiCyclic(i)
        ....:     assert A.is_isomorphic(B)
        sage: groups.presentation.DiCyclic(1)
        Traceback (most recent call last):
        ...
        ValueError: input integer must be greater than 1
    """
    n = Integer(n)
    if n < 2:
        raise ValueError('input integer must be greater than 1')

    F = FreeGroup(['a', 'b'])
    rls = F([1])**(2 * n), F([2, 2]) * F([-1])**n, F([-2, 1, 2, 1])
    return FinitelyPresentedGroup(F, rls)
示例#10
0
    def knot_group(self):
        """
        Computes the knot group using the Wirtinger presentation. 
        Returns a finitely presented group::

           sage: K = Link('3_1')
           sage: G = K.knot_group()
           sage: type(G)
           <class 'sage.groups.finitely_presented.FinitelyPresentedGroup_with_category'>

        """
        n = len(self.crossings)
        F = FreeGroup(n)
        g = list(F.gens())
        rels = []
        pieces = self._pieces()

        for z in self.crossings:
            for m, p in enumerate(pieces):
                for t, q in enumerate(p):
                    if q[0] == z:
                        if t == 0:
                            j = m
                        elif t == len(p) - 1:
                            i = m
                        else:
                            k = m
            i += 1
            j += 1
            k += 1
            if z.sign > 0:
                r = F([-k, i, k, -j])
            if z.sign < 0:
                r = F([k, i, -k, -j])
            rels.append(r)

        G = F / rels
        return G
示例#11
0
    def free(index_set=None, names=None, **kwds):
        r"""
        Return the free group.

        INPUT:

        - ``index_set`` -- (optional) an index set for the generators; if
          an integer, then this represents `\{0, 1, \ldots, n-1\}`

        - ``names`` -- a string or list/tuple/iterable of strings
          (default: ``'x'``); the generator names or name prefix

        When the index set is an integer or only variable names are given,
        this returns :class:`~sage.groups.free_group.FreeGroup_class`, which
        currently has more features due to the interface with GAP than
        :class:`~sage.groups.indexed_free_group.IndexedFreeGroup`.

        EXAMPLES::

            sage: Groups.free(index_set=ZZ)
            Free group indexed by Integer Ring
            sage: Groups().free(ZZ)
            Free group indexed by Integer Ring
            sage: Groups().free(5)
            Free Group on generators {x0, x1, x2, x3, x4}
            sage: F.<x,y,z> = Groups().free(); F
            Free Group on generators {x, y, z}
        """
        from sage.rings.all import ZZ
        if index_set in ZZ or (index_set is None and names is not None):
            from sage.groups.free_group import FreeGroup
            if names is None:
                return FreeGroup(index_set, **kwds)
            return FreeGroup(index_set, names, **kwds)

        from sage.groups.indexed_free_group import IndexedFreeGroup
        return IndexedFreeGroup(index_set, **kwds)
示例#12
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)
示例#13
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)
示例#14
0
def KleinFourPresentation():
    r"""
    Build the Klein group of order `4` as a finitely presented group.

    OUTPUT:

    Klein four group (`C_2 \times C_2`) as a finitely presented group.

    EXAMPLES::

        sage: K = groups.presentation.KleinFour(); K
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
    """
    F = FreeGroup(['a', 'b'])
    rls = F([1])**2, F([2])**2, F([-1]) * F([-2]) * F([1]) * F([2])
    return FinitelyPresentedGroup(F, rls)
示例#15
0
    def __init__(self, G):
        """
        Initialize ``self``.

        INPUT:

        - ``G`` -- a graph

        TESTS::

            sage: G = RightAngledArtinGroup(graphs.CycleGraph(5))
            sage: TestSuite(G).run()
        """
        self._graph = G
        F = FreeGroup(names=['v{}'.format(v) for v in self._graph.vertices()])
        CG = Graph(G).complement() # Make sure it's mutable
        CG.relabel() # Standardize the labels
        rels = tuple(F([i+1, j+1, -i-1, -j-1]) for i,j in CG.edges(False)) #+/- 1 for indexing
        FinitelyPresentedGroup.__init__(self, F, rels)
示例#16
0
def DihedralPresentation(n):
    r"""
    Build the Dihedral group of order `2n` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the set that `D_n` is acting on.

    OUTPUT:

    Dihedral group of order `2n`.

    EXAMPLES::

        sage: D = groups.presentation.Dihedral(7); D
        Finitely presented group < a, b | a^7, b^2, (a*b)^2 >
        sage: D.as_permutation_group().is_isomorphic(DihedralGroup(7))
        True

    TESTS::

        sage: n = 9
        sage: D = groups.presentation.Dihedral(n)
        sage: D.ngens() == 2
        True
        sage: groups.presentation.Dihedral(0)
        Traceback (most recent call last):
        ...
        ValueError: finitely presented group order must be positive
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('finitely presented group order must be positive')
    F = FreeGroup(['a', 'b'])
    rls = F([1])**n, F([2])**2, (F([1]) * F([2]))**2
    return FinitelyPresentedGroup(F, rls)
示例#17
0
def FinitelyGeneratedHeisenbergPresentation(n=1, p=0):
    r"""
    Return a finite presentation of the Heisenberg group.

    The Heisenberg group is the group of `(n+2) \times (n+2)` matrices
    over a ring `R` with diagonal elements equal to 1, first row and
    last column possibly nonzero, and all the other entries equal to zero.

    INPUT:

    - ``n`` -- the degree of the Heisenberg group

    - ``p`` -- (optional) a prime number, where we construct the
      Heisenberg group over the finite field `\ZZ/p\ZZ`
 
    OUTPUT:

    Finitely generated Heisenberg group over the finite field
    of order ``p`` or over the integers.

    .. SEEALSO::

        :class:`~sage.groups.matrix_gps.heisenberg.HeisenbergGroup`

    EXAMPLES::

        sage: H = groups.presentation.Heisenberg(); H
        Finitely presented group < x1, y1, z |
         x1*y1*x1^-1*y1^-1*z^-1, z*x1*z^-1*x1^-1, z*y1*z^-1*y1^-1 >
        sage: H.order()
        +Infinity
        sage: r1, r2, r3 = H.relations()
        sage: A = matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]])
        sage: B = matrix([[1, 0, 0], [0, 1, 1], [0, 0, 1]])
        sage: C = matrix([[1, 0, 1], [0, 1, 0], [0, 0, 1]])
        sage: r1(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r2(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r3(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: p = 3
        sage: Hp = groups.presentation.Heisenberg(p=3)
        sage: Hp.order() == p**3 
        True
        sage: Hnp = groups.presentation.Heisenberg(n=2, p=3)
        sage: len(Hnp.relations())
        13

    REFERENCES:

    - :wikipedia:`Heisenberg_group`
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('n must be a positive integer')

    # generators' names are x1, .., xn, y1, .., yn, z
    vx = ['x' + str(i) for i in range(1, n + 1)]
    vy = ['y' + str(i) for i in range(1, n + 1)]
    str_generators = ', '.join(vx + vy + ['z'])

    F = FreeGroup(str_generators)
    x = F.gens()[0:n]  # list of generators x1, x2, ..., xn
    y = F.gens()[n:2 * n]  # list of generators x1, x2, ..., xn
    z = F.gen(n * 2)

    def commutator(a, b):
        return a * b * a**-1 * b**-1

    # First set of relations: [xi, yi] = z
    r1 = [commutator(x[i], y[i]) * z**-1 for i in range(n)]
    # Second set of relations: [z, xi] = 1
    r2 = [commutator(z, x[i]) for i in range(n)]
    # Third set of relations: [z, yi] = 1
    r3 = [commutator(z, y[i]) for i in range(n)]
    # Fourth set of relations: [xi, yi] = 1 for i != j
    r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i != j]
    rls = r1 + r2 + r3 + r4

    from sage.sets.primes import Primes
    if p not in Primes() and p != 0:
        raise ValueError("p must be 0 or a prime number")
    if p > 0:
        rls += [w**p for w in F.gens()]
    return FinitelyPresentedGroup(F, tuple(rls))
示例#18
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))
示例#19
0
            def fundamental_group(self, simplify=True):
                r"""
                Return the fundamental group of this pointed simplicial set.

                INPUT:

                - ``simplify`` (bool, optional ``True``) -- if
                  ``False``, then return a presentation of the group
                  in terms of generators and relations. If ``True``,
                  the default, simplify as much as GAP is able to.

                Algorithm: we compute the edge-path group -- see
                Section 19 of [Kan1958]_ and
                :wikipedia:`Fundamental_group`. Choose a spanning tree
                for the connected component of the 1-skeleton
                containing the base point, and then the group's
                generators are given by the non-degenerate
                edges. There are two types of relations: `e=1` if `e`
                is in the spanning tree, and for every 2-simplex, if
                its faces are `e_0`, `e_1`, and `e_2`, then we impose
                the relation `e_0 e_1^{-1} e_2 = 1`, where we first
                set `e_i=1` if `e_i` is degenerate.

                EXAMPLES::

                    sage: S1 = simplicial_sets.Sphere(1)
                    sage: eight = S1.wedge(S1)
                    sage: eight.fundamental_group() # free group on 2 generators
                    Finitely presented group < e0, e1 |  >

                The fundamental group of a disjoint union of course depends on
                the choice of base point::

                    sage: T = simplicial_sets.Torus()
                    sage: K = simplicial_sets.KleinBottle()
                    sage: X = T.disjoint_union(K)

                    sage: X_0 = X.set_base_point(X.n_cells(0)[0])
                    sage: X_0.fundamental_group().is_abelian()
                    True
                    sage: X_1 = X.set_base_point(X.n_cells(0)[1])
                    sage: X_1.fundamental_group().is_abelian()
                    False

                    sage: RP3 = simplicial_sets.RealProjectiveSpace(3)
                    sage: RP3.fundamental_group()
                    Finitely presented group < e | e^2 >

                Compute the fundamental group of some classifying spaces::

                    sage: C5 = groups.misc.MultiplicativeAbelian([5])
                    sage: BC5 = C5.nerve()
                    sage: BC5.fundamental_group()
                    Finitely presented group < e0 | e0^5 >

                    sage: Sigma3 = groups.permutation.Symmetric(3)
                    sage: BSigma3 = Sigma3.nerve()
                    sage: pi = BSigma3.fundamental_group(); pi
                    Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 >
                    sage: pi.order()
                    6
                    sage: pi.is_abelian()
                    False

                The sphere has a trivial fundamental group::

                    sage: S2 = simplicial_sets.Sphere(2)
                    sage: S2.fundamental_group()
                    Finitely presented group <  |  >
                """
                # Import this here to prevent importing libgap upon startup.
                from sage.groups.free_group import FreeGroup
                skel = self.n_skeleton(2)

                graph = skel.graph()
                if not skel.is_connected():
                    graph = graph.subgraph(skel.base_point())

                edges = [e[2] for e in graph.edges()]
                spanning_tree = [e[2] for e in graph.min_spanning_tree()]
                gens = [e for e in edges if e not in spanning_tree]

                if not gens:
                    return FreeGroup([]).quotient([])

                gens_dict = dict(zip(gens, range(len(gens))))
                FG = FreeGroup(len(gens), 'e')
                rels = []

                for f in skel.n_cells(2):
                    z = dict()
                    for i, sigma in enumerate(skel.faces(f)):
                        if sigma in spanning_tree:
                            z[i] = FG.one()
                        elif sigma.is_degenerate():
                            z[i] = FG.one()
                        elif sigma in edges:
                            z[i] = FG.gen(gens_dict[sigma])
                        else:
                            # sigma is not in the correct connected component.
                            z[i] = FG.one()
                    rels.append(z[0] * z[1].inverse() * z[2])
                if simplify:
                    return FG.quotient(rels).simplified()
                else:
                    return FG.quotient(rels)
示例#20
0
def FinitelyGeneratedHeisenbergPresentation(n=1, p=0):
    r"""
    Return a finite presentation of the Heisenberg group.

    The Heisenberg group is the group of `(n+2) \times (n+2)` matrices
    over a ring `R` with diagonal elements equal to 1, first row and
    last column possibly nonzero, and all the other entries equal to zero.

    INPUT:

    - ``n`` -- the degree of the Heisenberg group

    - ``p`` -- (optional) a prime number, where we construct the
      Heisenberg group over the finite field `\ZZ/p\ZZ`
 
    OUTPUT:

    Finitely generated Heisenberg group over the finite field
    of order ``p`` or over the integers.

    .. SEEALSO::

        :class:`~sage.groups.matrix_gps.heisenberg.HeisenbergGroup`

    EXAMPLES::

        sage: H = groups.presentation.Heisenberg(); H
        Finitely presented group < x1, y1, z |
         x1*y1*x1^-1*y1^-1*z^-1, z*x1*z^-1*x1^-1, z*y1*z^-1*y1^-1 >
        sage: H.order()
        +Infinity
        sage: r1, r2, r3 = H.relations()
        sage: A = matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]])
        sage: B = matrix([[1, 0, 0], [0, 1, 1], [0, 0, 1]])
        sage: C = matrix([[1, 0, 1], [0, 1, 0], [0, 0, 1]])
        sage: r1(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r2(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r3(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: p = 3
        sage: Hp = groups.presentation.Heisenberg(p=3)
        sage: Hp.order() == p**3 
        True
        sage: Hnp = groups.presentation.Heisenberg(n=2, p=3)
        sage: len(Hnp.relations())
        13

    REFERENCES:

    - :wikipedia:`Heisenberg_group`
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('n must be a positive integer')

    # generators' names are x1, .., xn, y1, .., yn, z
    vx = ['x' + str(i) for i in range(1,n+1)]
    vy = ['y' + str(i) for i in range(1,n+1)]
    str_generators = ', '.join(vx + vy + ['z'])

    F = FreeGroup(str_generators)
    x = F.gens()[0:n] # list of generators x1, x2, ..., xn
    y = F.gens()[n:2*n] # list of generators x1, x2, ..., xn
    z = F.gen(n*2)

    def commutator(a, b): return a * b * a**-1 * b**-1
    # First set of relations: [xi, yi] = z
    r1 = [commutator(x[i], y[i]) * z**-1 for i in range(n)]
    # Second set of relations: [z, xi] = 1
    r2 = [commutator(z, x[i]) for i in range(n)]
    # Third set of relations: [z, yi] = 1
    r3 = [commutator(z, y[i]) for i in range(n)]
    # Fourth set of relations: [xi, yi] = 1 for i != j
    r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i!=j]
    rls = r1 + r2 + r3 + r4

    from sage.sets.primes import Primes
    if p not in Primes() and p != 0:
        raise ValueError("p must be 0 or a prime number")
    if p > 0:
        rls += [w**p for w in F.gens()]
    return FinitelyPresentedGroup(F, tuple(rls))
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, a Zariski-VanKampen presentation is returned.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    bm = braid_monodromy(f)
    n = bm[0].parent().strands()
    F = FreeGroup(n)
    R = [x * b / x for x in F.gens() for b in bm]
    if projective:
        R.append(prod(F.gens()))
    G = F / R
    if simplified:
        return G.simplified()
    return G
示例#22
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
示例#23
0
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, the returned presentation has as
    many generators as degree of the polynomial times the points in the
    base used to create the segments that surround the discriminant. In
    this case, the generators are granted to be meridians of the curve.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    (x, y) = f.variables()
    F = f.base_ring()
    g = f.factor().radical().prod()
    d = g.degree(y)
    while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    segs = segments(disc)
    vertices = list(set(flatten(segs)))
    Faux = FreeGroup(d)
    F = FreeGroup(d * len(vertices))
    rels = []
    if projective:
        rels.append(prod(F.gen(i) for i in range(d)))
    braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        b = braidcomputed[1]
        i = vertices.index(seg[0])
        j = vertices.index(seg[1])
        for k in range(d):
            el1 = Faux([k + 1]) * b.inverse()
            el2 = k + 1
            w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
            w2 = F([d*j + el2])
            rels.append(w1/w2)
    G = F / rels
    if simplified:
        return G.simplified()
    else:
        return G
示例#24
0
            def fundamental_group(self, simplify=True):
                r"""
                Return the fundamental group of this pointed simplicial set.

                INPUT:

                - ``simplify`` (bool, optional ``True``) -- if
                  ``False``, then return a presentation of the group
                  in terms of generators and relations. If ``True``,
                  the default, simplify as much as GAP is able to.

                Algorithm: we compute the edge-path group -- see
                Section 19 of [Kan1958]_ and
                :wikipedia:`Fundamental_group`. Choose a spanning tree
                for the connected component of the 1-skeleton
                containing the base point, and then the group's
                generators are given by the non-degenerate
                edges. There are two types of relations: `e=1` if `e`
                is in the spanning tree, and for every 2-simplex, if
                its faces are `e_0`, `e_1`, and `e_2`, then we impose
                the relation `e_0 e_1^{-1} e_2 = 1`, where we first
                set `e_i=1` if `e_i` is degenerate.

                EXAMPLES::

                    sage: S1 = simplicial_sets.Sphere(1)
                    sage: eight = S1.wedge(S1)
                    sage: eight.fundamental_group() # free group on 2 generators
                    Finitely presented group < e0, e1 |  >

                The fundamental group of a disjoint union of course depends on
                the choice of base point::

                    sage: T = simplicial_sets.Torus()
                    sage: K = simplicial_sets.KleinBottle()
                    sage: X = T.disjoint_union(K)

                    sage: X_0 = X.set_base_point(X.n_cells(0)[0])
                    sage: X_0.fundamental_group().is_abelian()
                    True
                    sage: X_1 = X.set_base_point(X.n_cells(0)[1])
                    sage: X_1.fundamental_group().is_abelian()
                    False

                    sage: RP3 = simplicial_sets.RealProjectiveSpace(3)
                    sage: RP3.fundamental_group()
                    Finitely presented group < e | e^2 >

                Compute the fundamental group of some classifying spaces::

                    sage: C5 = groups.misc.MultiplicativeAbelian([5])
                    sage: BC5 = C5.nerve()
                    sage: BC5.fundamental_group()
                    Finitely presented group < e0 | e0^5 >

                    sage: Sigma3 = groups.permutation.Symmetric(3)
                    sage: BSigma3 = Sigma3.nerve()
                    sage: pi = BSigma3.fundamental_group(); pi
                    Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 >
                    sage: pi.order()
                    6
                    sage: pi.is_abelian()
                    False
                """
                # Import this here to prevent importing libgap upon startup.
                from sage.groups.free_group import FreeGroup
                skel = self.n_skeleton(2)

                graph = skel.graph()
                if not skel.is_connected():
                    graph = graph.subgraph(skel.base_point())

                edges = [e[2] for e in graph.edges()]
                spanning_tree = [e[2] for e in graph.min_spanning_tree()]
                gens = [e for e in edges if e not in spanning_tree]

                if not gens:
                    return gap.TrivialGroup()

                gens_dict = dict(zip(gens, range(len(gens))))
                FG = FreeGroup(len(gens), 'e')
                rels = []

                for f in skel.n_cells(2):
                    z = dict()
                    for i, sigma in enumerate(skel.faces(f)):
                        if sigma in spanning_tree:
                            z[i] = FG.one()
                        elif sigma.is_degenerate():
                            z[i] = FG.one()
                        elif sigma in edges:
                            z[i] = FG.gen(gens_dict[sigma])
                        else:
                            # sigma is not in the correct connected component.
                            z[i] = FG.one()
                    rels.append(z[0]*z[1].inverse()*z[2])
                if simplify:
                    return FG.quotient(rels).simplified()
                else:
                    return FG.quotient(rels)
示例#25
0
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, the returned presentation has as
    many generators as degree of the polynomial times the points in the
    base used to create the segments that surround the discriminant. In
    this case, the generators are granted to be meridians of the curve.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    (x, y) = f.variables()
    F = f.base_ring()
    g = f.factor().radical().prod()
    d = g.degree(y)
    while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    segs = segments(disc)
    vertices = list(set(flatten(segs)))
    Faux = FreeGroup(d)
    F = FreeGroup(d * len(vertices))
    rels = []
    if projective:
        rels.append(prod(F.gen(i) for i in range(d)))
    braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        b = braidcomputed[1]
        i = vertices.index(seg[0])
        j = vertices.index(seg[1])
        for k in range(d):
            el1 = Faux([k + 1]) * b.inverse()
            el2 = k + 1
            w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
            w2 = F([d*j + el2])
            rels.append(w1/w2)
    G = F / rels
    if simplified:
        return G.simplified()
    else:
        return G
示例#26
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))