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)
    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
Exemple #3
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 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 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*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b >

    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*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b >

    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 = list(Set(F.gens()).subsets(2))
    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))
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*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b >

    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*c^-1*a*c, a^-1*b^-1*a*b, c^-1*b^-1*c*b >

    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 x (=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([name_gen.next() 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 = list(Set(F.gens()).subsets(2))
    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))
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