Пример #1
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField

        UCF = UniversalCyclotomicField()
        if UCF.has_coerce_map_from(base_ring):
            R = UCF
        else:
            R = base_ring
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(-2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(
            MS,
            entries={(i, j): val(mat[i, j]) for i in range(n) for j in range(n) if mat[i, j] != 2},
            coerce=True,
            copy=True,
        )
        bilinear.set_immutable()
        return bilinear
Пример #2
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
        UCF = UniversalCyclotomicField()

        if R is None:
            R = UCF
        # if UCF.has_coerce_map_from(base_ring):
        #     R = UCF
        # else:
        #     R = base_ring

        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(
                -2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(MS,
                      entries={(i, j): val(mat[i, j])
                               for i in range(n) for j in range(n)
                               if mat[i, j] != 2},
                      coerce=True,
                      copy=True)
        bilinear.set_immutable()
        return bilinear
Пример #3
0
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=UniversalCyclotomicField())
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True
        """
        data = CoxeterMatrix(data, index_set=index_set)

        if base_ring is None:
            base_ring = UniversalCyclotomicField()
        return super(CoxeterMatrixGroup, cls).__classcall__(cls,
                                     data, base_ring, data.index_set())
Пример #4
0
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=ZZ)
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True
        """
        data = CoxeterMatrix(data, index_set=index_set)

        if base_ring is None:
            if data.is_simply_laced():
                base_ring = ZZ
            elif data.is_finite():
                letter = data.coxeter_type().cartan_type().type()
                if letter in ['B', 'C', 'F']:
                    base_ring = QuadraticField(2)
                elif letter == 'G':
                    base_ring = QuadraticField(3)
                elif letter == 'H':
                    base_ring = QuadraticField(5)
                else:
                    base_ring = UniversalCyclotomicField()
            else:
                base_ring = UniversalCyclotomicField()
        return super(CoxeterMatrixGroup,
                     cls).__classcall__(cls, data, base_ring, data.index_set())
Пример #5
0
    def H_value(self, p, f, t, ring=None):
        """
        Return the trace of the Frobenius, computed in terms of Gauss sums
        using the hypergeometric trace formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``ring`` -- optional (default ``UniversalCyclotomicfield``)

        The ring could be also ``ComplexField(n)`` or ``QQbar``.

        OUTPUT:

        an integer

        .. WARNING::

            This is apparently working correctly as can be tested
            using ComplexField(70) as value ring.

            Using instead UniversalCyclotomicfield, this is much
            slower than the `p`-adic version :meth:`padic_H_value`.

        EXAMPLES:

        With values in the UniversalCyclotomicField (slow)::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.H_value(7,i,-1) for i in range(1,3)]  # not tested
            [0, -476]
            sage: [H.H_value(11,i,-1) for i in range(1,3)]  # not tested
            [0, -4972]
            sage: [H.H_value(13,i,-1) for i in range(1,3)]  # not tested
            [-84, -1420]

        With values in ComplexField::

            sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)]
            [-4, 276]

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.H_value(5,1,QQ(i)) for i in range(2,5)]
            [-4, 1, -4]

        REFERENCES:

        - [BeCoMe]_ (Theorem 1.3)
        - [Benasque2009]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.H_value(p, f, ~t, ring)
        if ring is None:
            ring = UniversalCyclotomicField()
        gamma = self.gamma_array()
        q = p ** f

        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2
        M = self.M_value()

        Fq = GF(q)
        gen = Fq.multiplicative_generator()
        zeta_q = ring.zeta(q - 1)

        tM = Fq(M / t)
        for k in range(q - 1):
            if gen ** k == tM:
                teich = zeta_q ** k
                break

        gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)]

        sigma = sum(q**(D + m[0] - m[r]) *
                    prod(gauss_table[(-v * r) % (q - 1)]**gv
                         for v, gv in gamma.items()) *
                    teich ** r
                    for r in range(q - 1))
        resu = ZZ(-1) ** m[0] / (1 - q) * sigma
        if not ring.is_exact():
            resu = resu.real_part().round()
        return resu
Пример #6
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
        UCF = UniversalCyclotomicField()

        if R is None:
            R = UCF
        # if UCF.has_coerce_map_from(base_ring):
        #     R = UCF
        # else:
        #     R = base_ring

        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        E = UCF.gen
        if R is UCF:

            def val(x):
                if x > -1:
                    return (E(2 * x) + ~E(2 * x)) / R(-2)
                else:
                    return R(x)
        elif is_QuadraticField(R):

            def val(x):
                if x > -1:
                    return R(
                        (E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) / R(-2)
                else:
                    return R(x)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x > -1:
                    return -R(cos(pi / SR(x)))
                else:
                    return R(x)

        entries = [
            SparseEntry(i, j, val(mat[i, j])) for i in range(n)
            for j in range(n) if mat[i, j] != 2
        ]
        bilinear = Matrix(R, n, entries)
        bilinear.set_immutable()
        return bilinear
Пример #7
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        n = coxeter_matrix.rank()
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        E = UniversalCyclotomicField().gen
        if base_ring is UniversalCyclotomicField():

            def val(x):
                if x == -1:
                    return 2
                else:
                    return E(2 * x) + ~E(2 * x)
        elif is_QuadraticField(base_ring):

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring(
                        (E(2 * x) + ~E(2 * x)).to_cyclotomic_field())
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring(2 * cos(pi / x))

        gens = [
            MS.one() +
            MC(MS,
               entries={(i, j): val(coxeter_matrix[index_set[i], index_set[j]])
                        for j in range(n)},
               coerce=True,
               copy=True) for i in range(n)
        ]
        # Make the generators dense matrices for consistency and speed
        gens = [g.dense_matrix() for g in gens]
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        if self._matrix.is_finite():
            category = category.Finite()
        else:
            category = category.Infinite()
        self._index_set_inverse = {
            i: ii
            for ii, i in enumerate(self._matrix.index_set())
        }
        FinitelyGeneratedMatrixGroup_generic.__init__(self,
                                                      ZZ(n),
                                                      base_ring,
                                                      gens,
                                                      category=category)
def real_characters(G):
    r"""
    Return a pair ``(table of characters, character degrees)`` for the
    group ``G``.

    OUTPUT:

    - table of characters - a list of characters. Each character is represented
      as the list of its values on conjugacy classes. The order of conjugacy
      classes is the same as the one returned by GAP.

    - degrees - the list of degrees of the characters

    EXAMPLES::

        sage: from surface_dynamics.misc.group_representation import real_characters
        sage: T, deg = real_characters(AlternatingGroup(5))
        sage: T
        [(1, 1, 1, 1, 1),
         (3, -1, 0, -E(5) - E(5)^4, -E(5)^2 - E(5)^3),
         (3, -1, 0, -E(5)^2 - E(5)^3, -E(5) - E(5)^4),
         (4, 0, 1, -1, -1),
         (5, 1, -1, 0, 0)]
        sage: set(parent(x) for chi in T for x in chi)
        {Universal Cyclotomic Field}
        sage: deg
        [1, 3, 3, 4, 5]

        sage: T, deg = real_characters(CyclicPermutationGroup(6))
        sage: T
        [(1, 1, 1, 1, 1, 1),
         (1, -1, 1, -1, 1, -1),
         (2, -1, -1, 2, -1, -1),
         (2, 1, -1, -2, -1, 1)]
        sage: deg
        [1, 1, 1, 1]
    """
    from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField

    G = libgap(G)
    UCF = UniversalCyclotomicField()
    n = G.ConjugacyClasses().Length()
    Tgap = G.CharacterTable().Irr()
    degrees = [chi.Degree().sage() for chi in Tgap]
    Tgap = [tuple(UCF(chi[j]) for j in range(n)) for chi in Tgap]

    real_T = []
    real_degrees = []
    seen = set()
    for i, chi in enumerate(Tgap):
        if chi in seen:
            continue

        real_degrees.append(degrees[i])
        if all(x.is_real() for x in chi):
            real_T.append(chi)
            seen.add(chi)
        else:
            seen.add(chi)
            chi_bar = tuple(z.conjugate() for z in chi)
            seen.add(chi_bar)
            real_T.append(tuple(chi[j] + chi[j].conjugate() for j in range(n)))

    return (real_T, real_degrees)
    def H_value(self, p, f, t, ring=None):
        """
        Return the trace of the Frobenius, computed in terms of Gauss sums
        using the hypergeometric trace formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``ring`` -- optional (default ``UniversalCyclotomicfield``)

        The ring could be also ``ComplexField(n)`` or ``QQbar``.

        OUTPUT:

        an integer

        .. WARNING::

            This is apparently working correctly as can be tested
            using ComplexField(70) as value ring.

            Using instead UniversalCyclotomicfield, this is much
            slower than the `p`-adic version :meth:`padic_H_value`.

        EXAMPLES:

        With values in the UniversalCyclotomicField (slow)::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.H_value(7,i,-1) for i in range(1,3)]  # not tested
            [0, -476]
            sage: [H.H_value(11,i,-1) for i in range(1,3)]  # not tested
            [0, -4972]
            sage: [H.H_value(13,i,-1) for i in range(1,3)]  # not tested
            [-84, -1420]

        With values in ComplexField::

            sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)]
            [-4, 276]

        REFERENCES:

        - [BeCoMe]_ (Theorem 1.3)
        - [Benasque2009]_
        """
        alpha = self._alpha
        beta = self._beta
        if 0 in alpha:
            H = self.swap_alpha_beta()
            return(H.H_value(p, f, ~t, ring))
        if ring is None:
            ring = UniversalCyclotomicField()
        t = QQ(t)
        gamma = self.gamma_array()
        q = p ** f

        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2
        M = self.M_value()

        Fq = GF(q)
        gen = Fq.multiplicative_generator()
        zeta_q = ring.zeta(q - 1)

        tM = Fq(M / t)
        for k in range(q - 1):
            if gen ** k == tM:
                teich = zeta_q ** k
                break

        gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)]

        sigma = sum(q**(D + m[0] - m[r]) *
                    prod(gauss_table[(-v * r) % (q - 1)] ** gv
                         for v, gv in gamma.items()) *
                    teich ** r
                    for r in range(q - 1))
        resu = ZZ(-1) ** m[0] / (1 - q) * sigma
        if not ring.is_exact():
            resu = resu.real_part().round()
        return resu
Пример #10
0
        def permutahedron(self, point=None, base_ring=None):
            r"""
            Return the permutahedron of ``self``,

            This is the convex hull of the point ``point`` in the weight
            basis under the action of ``self`` on the underlying vector
            space `V`.

            .. SEEALSO::

                :meth:`~sage.combinat.root_system.reflection_group_real.permutahedron`

            INPUT:

            - ``point`` -- optional, a point given by its coordinates in
              the weight basis (default is `(1, 1, 1, \ldots)`)
            - ``base_ring`` -- optional, the base ring of the polytope

            .. NOTE::

                The result is expressed in the root basis coordinates.

            .. NOTE::

                If function is too slow, switching the base ring to
                :class:`RDF` will almost certainly speed things up.

            EXAMPLES::

                sage: W = CoxeterGroup(['H',3], base_ring=RDF)
                sage: W.permutahedron()
                doctest:warning
                ...
                UserWarning: This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.
                A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 120 vertices

                sage: W = CoxeterGroup(['I',7])
                sage: W.permutahedron()
                A 2-dimensional polyhedron in AA^2 defined as the convex hull of 14 vertices
                sage: W.permutahedron(base_ring=RDF)
                A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 14 vertices

                sage: W = ReflectionGroup(['A',3])                          # optional - gap3
                sage: W.permutahedron()                                     # optional - gap3
                A 3-dimensional polyhedron in QQ^3 defined as the convex hull
                of 24 vertices

                sage: W = ReflectionGroup(['A',3],['B',2])                  # optional - gap3
                sage: W.permutahedron()                                     # optional - gap3
                A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 192 vertices

            TESTS::

                sage: W = ReflectionGroup(['A',3])                          # optional - gap3
                sage: W.permutahedron([3,5,8])                              # optional - gap3
                A 3-dimensional polyhedron in QQ^3 defined as the convex hull
                of 24 vertices


            .. PLOT::
                :width: 300 px

                W = CoxeterGroup(['I',7])
                p = W.permutahedron()
                sphinx_plot(p)

            """
            n = self.one().canonical_matrix().rank()
            weights = self.fundamental_weights()
            if point is None:
                from sage.rings.integer_ring import ZZ
                point = [ZZ.one()] * n
            v = sum(point[i - 1] * weights[i] for i in weights.keys())
            from sage.geometry.polyhedron.constructor import Polyhedron
            from sage.rings.qqbar import AA, QQbar
            from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
            vertices = [v * w for w in self]
            if base_ring is None and v.base_ring() in [
                    UniversalCyclotomicField(), QQbar
            ]:
                vertices = [v.change_ring(AA) for v in vertices]
                base_ring = AA
            return Polyhedron(vertices=vertices, base_ring=base_ring)
Пример #11
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2 * x) + ~base_ring.gen(
                2 * x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2 * cos(pi / x)
                                      ) if x != -1 else base_ring(2)
        gens = [
            MS.one() + MC(MS,
                          entries={(i, j): val(coxeter_matrix[i, j])
                                   for j in range(n)},
                          coerce=True,
                          copy=True) for i in range(n)
        ]
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        # This describes the bilinear form corresponding to this
        # Coxeter system, and might lead us out of our base ring.
        base_field = base_ring.fraction_field()
        MS2 = MatrixSpace(base_field, n, sparse=True)
        MC2 = MS2._get_matrix_class()
        self._bilinear = MC2(MS2,
                             entries={
                                 (i, j):
                                 val(coxeter_matrix[i, j]) / base_field(-2)
                                 for i in range(n) for j in range(n)
                                 if coxeter_matrix[i, j] != 2
                             },
                             coerce=True,
                             copy=True)
        self._bilinear.set_immutable()
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        is_finite = self._finite_recognition()
        if is_finite:
            category = category.Finite()
        else:
            category = category.Infinite()
        FinitelyGeneratedMatrixGroup_generic.__init__(self,
                                                      n,
                                                      base_ring,
                                                      gens,
                                                      category=category)
Пример #12
0
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=UniversalCyclotomicField())
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True

        Check with `\infty` because of the hack of using `-1` to represent
        `\infty` in the Coxeter matrix::

            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W1 = CoxeterGroup(matrix([[1, 3, 2], [3,1,-1], [2,-1,1]]))
            sage: W2 = CoxeterGroup(G)
            sage: W1 is W2
            True
            sage: CoxeterGroup(W1.coxeter_graph()) is W1
            True
        """
        if isinstance(data, CartanType_abstract):
            if index_set is None:
                index_set = data.index_set()
            data = data.coxeter_matrix()
        elif isinstance(data, Graph):
            G = data
            n = G.num_verts()

            # Setup the basis matrix as all 2 except 1 on the diagonal
            data = matrix(ZZ, [[2] * n] * n)
            for i in range(n):
                data[i, i] = ZZ.one()

            verts = G.vertices()
            for e in G.edges():
                m = e[2]
                if m is None:
                    m = 3
                elif m == infinity or m == -1:  # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    m = -1
                elif m <= 1:
                    raise ValueError("invalid Coxeter graph label")
                i = verts.index(e[0])
                j = verts.index(e[1])
                data[j, i] = data[i, j] = m

            if index_set is None:
                index_set = G.vertices()
        else:
            try:
                data = matrix(data)
            except (ValueError, TypeError):
                data = CartanType(data).coxeter_matrix()
            if not data.is_symmetric():
                raise ValueError("the Coxeter matrix is not symmetric")
            if any(d != 1 for d in data.diagonal()):
                raise ValueError("the Coxeter matrix diagonal is not all 1")
            if any(val <= 1 and val != -1 for i, row in enumerate(data.rows())
                   for val in row[i + 1:]):
                raise ValueError("invalid Coxeter label")

            if index_set is None:
                index_set = range(data.nrows())

        if base_ring is None:
            base_ring = UniversalCyclotomicField()
        data.set_immutable()
        return super(CoxeterMatrixGroup,
                     cls).__classcall__(cls, data, base_ring, tuple(index_set))