示例#1
0
def gap_handle(x):
    """
    Return a low-level libgap handle to the corresponding GAP object.

    EXAMPLES::

        sage: from mygap import mygap, gap_handle
        sage: h = libgap.GF(3)
        sage: F = mygap(h)
        sage: gap_handle(F) is h
        True
        sage: l = gap_handle([1,2,F])
        sage: l
        [ 1, 2, GF(3) ]
        sage: l[0] == 1
        True
        sage: l[2] == h
        True

    .. TODO::

        Maybe we just want, for x a glorified hand, libgap(x) to
        return the corresponding low level handle
    """
    from mygap import GAPObject
    if isinstance(x, (list, tuple)):
        return libgap([gap_handle(y) for y in x])
    elif isinstance(x, GAPObject):
        return x.gap()
    else:
        return libgap(x)
def gap_handle(x):
    """
    Return a low-level libgap handle to the corresponding GAP object.

    EXAMPLES::

        sage: from mygap import mygap
        sage: from mmt import gap_handle
        sage: h = libgap.GF(3)
        sage: F = mygap(h)
        sage: gap_handle(F) is h
        True
        sage: l = gap_handle([1,2,F])
        sage: l
        [ 1, 2, GF(3) ]
        sage: l[0] == 1
        True
        sage: l[2] == h
        True

    .. TODO::

        Maybe we just want, for x a glorified hand, libgap(x) to
        return the corresponding low level handle
    """
    from mygap import GAPObject
    if isinstance(x, (list, tuple)):
        return libgap([gap_handle(y) for y in x])
    elif isinstance(x, GAPObject):
        return x.gap()
    else:
        return libgap(x)
示例#3
0
    def __init__(self, n=1, R=0):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: H = groups.matrix.Heisenberg(n=2, R=5)
            sage: TestSuite(H).run()  # long time
            sage: H = groups.matrix.Heisenberg(n=2, R=4)
            sage: TestSuite(H).run()  # long time
            sage: H = groups.matrix.Heisenberg(n=3)
            sage: TestSuite(H).run(max_runs=30, skip="_test_elements")  # long time
            sage: H = groups.matrix.Heisenberg(n=2, R=GF(4))
            sage: TestSuite(H).run()  # long time
        """
        def elementary_matrix(i, j, val, MS):
            elm = copy(MS.one())
            elm[i, j] = val
            elm.set_immutable()
            return elm

        self._n = n
        self._ring = R
        # We need the generators of the ring as a commutative additive group
        if self._ring is ZZ:
            ring_gens = [self._ring.one()]
        else:
            if self._ring.cardinality() == self._ring.characteristic():
                ring_gens = [self._ring.one()]
            else:
                # This is overkill, but is the only way to ensure
                #   we get all of the elements
                ring_gens = list(self._ring)

        dim = ZZ(n + 2)
        MS = MatrixSpace(self._ring, dim)
        gens_x = [
            elementary_matrix(0, j, gen, MS) for j in range(1, dim - 1)
            for gen in ring_gens
        ]
        gens_y = [
            elementary_matrix(i, dim - 1, gen, MS) for i in range(1, dim - 1)
            for gen in ring_gens
        ]
        gen_z = [elementary_matrix(0, dim - 1, gen, MS) for gen in ring_gens]
        gens = gens_x + gens_y + gen_z

        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(single_gen) for single_gen in gens]
        gap_group = libgap.Group(gap_gens)

        cat = Groups().FinitelyGenerated()
        if self._ring in Rings().Finite():
            cat = cat.Finite()

        FinitelyGeneratedMatrixGroup_gap.__init__(self,
                                                  ZZ(dim),
                                                  self._ring,
                                                  gap_group,
                                                  category=cat)
示例#4
0
    def __init__(self, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: G = groups.matrix.BinaryDihedral(4)
            sage: TestSuite(G).run()
        """
        self._n = n

        if n % 2 == 0:
            R = CyclotomicField(2*n)
            zeta = R.gen()
            i = R.gen()**(n//2)
        else:
            R = CyclotomicField(4*n)
            zeta = R.gen()**2
            i = R.gen()**n

        MS = MatrixSpace(R, 2)
        zero = R.zero()
        gens = [ MS([zeta, zero, zero, ~zeta]), MS([zero, i, i, zero]) ]

        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)

        FinitelyGeneratedMatrixGroup_gap.__init__(self, ZZ(2), R, gap_group, category=Groups().Finite())
示例#5
0
    def _cc_mats(self):
        r"""
        The projection given by the conjugacy class.

        This is cached to speed up the computation of the projection matrices.
        See :meth:`~flatsurf.misc.group_representation.conjugacy_class_matrix`
        for more informations.

        TESTS::

            sage: from surface_dynamics.all import *
            sage: p = iet.GeneralizedPermutation('a b b','c c a')
            sage: c = p.cover(['(1,2,3)','(1,3,2)','()'])
            sage: c._cc_mats()
            (
            [1 0 0]  [0 1 0]  [0 0 1]
            [0 1 0]  [0 0 1]  [1 0 0]
            [0 0 1], [1 0 0], [0 1 0]
            )
        """
        from surface_dynamics.misc.group_representation import conjugacy_class_matrix
        G = self.automorphism_group()
        mats = []
        for cl in libgap(G).ConjugacyClasses():
            m = conjugacy_class_matrix(cl, self._degree_cover)
            m.set_immutable()
            mats.append(m)
        return tuple(mats)
示例#6
0
    def __init__(self, free_group, relations):
        """
        The Python constructor.

        TESTS::

            sage: G = FreeGroup('a, b')
            sage: H = G / (G([1]), G([2])^3)
            sage: H
            Finitely presented group < a, b | a, b^3 >

            sage: F = FreeGroup('a, b')
            sage: J = F / (F([1]), F([2, 2, 2]))
            sage: J is H
            True

            sage: TestSuite(H).run()
            sage: TestSuite(J).run()
        """
        from sage.groups.free_group import is_FreeGroup
        assert is_FreeGroup(free_group)
        assert isinstance(relations, tuple)
        self._free_group = free_group
        self._relations = relations
        self._assign_names(free_group.variable_names())
        parent_gap = free_group.gap() / libgap(
            [rel.gap() for rel in relations])
        ParentLibGAP.__init__(self, parent_gap)
        Group.__init__(self)
示例#7
0
    def restrict(self, H):
        r"""
        Return the restricted character.

        INPUT:

        - ``H`` -- a subgroup of the underlying group of ``self``.

        OUTPUT:

        A :class:`ClassFunction` of ``H`` defined by restriction.

        EXAMPLES::

            sage: G = SymmetricGroup(5)
            sage: chi = ClassFunction(G, [3, -3, -1, 0, 0, -1, 3]); chi
            Character of Symmetric group of order 5! as a permutation group
            sage: H = G.subgroup([(1,2,3), (1,2), (4,5)])
            sage: chi.restrict(H)
            Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)]
            sage: chi.restrict(H).values()
            [3, -3, -3, -1, 0, 0]
        """
        try:
            gapH = H.gap()
        except AttributeError:
            from sage.libs.gap.libgap import libgap
            gapH = libgap(H)
        rest = self._gap_classfunction.RestrictedClassFunction(gapH)
        return ClassFunction(H, rest)
示例#8
0
    def __init__(self, free_group, relations):
        """
        The Python constructor

        TESTS::

            sage: G = FreeGroup('a, b')
            sage: H = G / (G([1]), G([2])^3)
            sage: H
            Finitely presented group < a, b | a, b^3 >

            sage: F = FreeGroup('a, b')
            sage: J = F / (F([1]), F([2, 2, 2]))
            sage: J is H
            True

            sage: TestSuite(H).run()
            sage: TestSuite(J).run()
        """
        from sage.groups.free_group import is_FreeGroup
        assert is_FreeGroup(free_group)
        assert isinstance(relations, tuple)
        self._free_group = free_group
        self._relations = relations
        self._assign_names(free_group.variable_names())
        parent_gap = free_group.gap() / libgap([ rel.gap() for rel in relations])
        ParentLibGAP.__init__(self, parent_gap)
        Group.__init__(self)
示例#9
0
def to_libgap(x):
    """
    Helper to convert ``x`` to a LibGAP matrix or matrix group
    element.

    Deprecated; use the ``x.gap()`` method or ``libgap(x)`` instead.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.morphism import to_libgap
        sage: to_libgap(GL(2,3).gen(0))
        doctest:...: DeprecationWarning: this function is deprecated.
         Use x.gap() or libgap(x) instead.
        See https://trac.sagemath.org/25444 for details.
        [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]
        sage: to_libgap(matrix(QQ, [[1,2],[3,4]]))
        [ [ 1, 2 ], [ 3, 4 ] ]
    """
    from sage.misc.superseded import deprecation
    deprecation(
        25444, "this function is deprecated."
        " Use x.gap() or libgap(x) instead.")
    try:
        return x.gap()
    except AttributeError:
        from sage.libs.gap.libgap import libgap
        return libgap(x)
示例#10
0
    def __init__(self, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: G = groups.matrix.BinaryDihedral(4)
            sage: TestSuite(G).run()
        """
        self._n = n

        if n % 2 == 0:
            R = CyclotomicField(2 * n)
            zeta = R.gen()
            i = R.gen()**(n // 2)
        else:
            R = CyclotomicField(4 * n)
            zeta = R.gen()**2
            i = R.gen()**n

        MS = MatrixSpace(R, 2)
        zero = R.zero()
        gens = [MS([zeta, zero, zero, ~zeta]), MS([zero, i, i, zero])]

        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)

        FinitelyGeneratedMatrixGroup_gap.__init__(self,
                                                  ZZ(2),
                                                  R,
                                                  gap_group,
                                                  category=Groups().Finite())
示例#11
0
文件: morphism.py 项目: sagemath/sage
def to_libgap(x):
    """
    Helper to convert ``x`` to a LibGAP matrix or matrix group
    element.

    Deprecated; use the ``x.gap()`` method or ``libgap(x)`` instead.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.morphism import to_libgap
        sage: to_libgap(GL(2,3).gen(0))
        doctest:...: DeprecationWarning: this function is deprecated.
         Use x.gap() or libgap(x) instead.
        See https://trac.sagemath.org/25444 for details.
        [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]
        sage: to_libgap(matrix(QQ, [[1,2],[3,4]]))
        [ [ 1, 2 ], [ 3, 4 ] ]
    """
    from sage.misc.superseded import deprecation
    deprecation(25444, "this function is deprecated."
                " Use x.gap() or libgap(x) instead.")
    try:
        return x.gap()
    except AttributeError:
        from sage.libs.gap.libgap import libgap
        return libgap(x)
示例#12
0
    def restrict(self, H):
        r"""
        Return the restricted character.

        INPUT:

        - ``H`` -- a subgroup of the underlying group of ``self``.

        OUTPUT:

        A :class:`ClassFunction` of ``H`` defined by restriction.

        EXAMPLES::

            sage: G = SymmetricGroup(5)
            sage: chi = ClassFunction(G, [3, -3, -1, 0, 0, -1, 3]); chi
            Character of Symmetric group of order 5! as a permutation group
            sage: H = G.subgroup([(1,2,3), (1,2), (4,5)])
            sage: chi.restrict(H)
            Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)]
            sage: chi.restrict(H).values()
            [3, -3, -3, -1, 0, 0]
        """
        try:
            gapH = H.gap()
        except AttributeError:
            from sage.libs.gap.libgap import libgap
            gapH = libgap(H)
        rest = self._gap_classfunction.RestrictedClassFunction(gapH)
        return ClassFunction(H, rest)
示例#13
0
    def _cc_mats(self):
        r"""
        The projection given by the conjugacy class.

        This is cached to speed up the computation of the projection matrices.
        See :meth:`~flatsurf.misc.group_representation.conjugacy_class_matrix`
        for more informations.

        TESTS::

            sage: from surface_dynamics.all import *
            sage: p = iet.GeneralizedPermutation('a b b','c c a')
            sage: c = p.cover(['(1,2,3)','(1,3,2)','()'])
            sage: c._cc_mats()
            (
            [1 0 0]  [0 1 0]  [0 0 1]
            [0 1 0]  [0 0 1]  [1 0 0]
            [0 0 1], [1 0 0], [0 1 0]
            )
        """
        from surface_dynamics.misc.group_representation import conjugacy_class_matrix
        G = self.automorphism_group()
        mats = []
        for cl in libgap(G).ConjugacyClasses():
            m = conjugacy_class_matrix(cl, self._degree_cover)
            m.set_immutable()
            mats.append(m)
        return tuple(mats)
    def kernel(self):
        """
        Only works for finite groups.

        .. TODO::

            not done yet; returns a gap object but should return a Sage group.

        EXAMPLES::

            sage: H = AbelianGroup(3,[2,3,4],names="abc"); H
            Multiplicative Abelian group isomorphic to C2 x C3 x C4
            sage: a,b,c = H.gens()
            sage: G = AbelianGroup(2,[2,3],names="xy"); G
            Multiplicative Abelian group isomorphic to C2 x C3
            sage: x,y = G.gens()
            sage: phi = AbelianGroupMorphism(G,H,[x,y],[a,b])
            sage: phi.kernel()
            Group([  ])

            sage: H = AbelianGroup(3,[2,2,2],names="abc")
            sage: a,b,c = H.gens()
            sage: G = AbelianGroup(2,[2,2],names="x")
            sage: x,y = G.gens()
            sage: phi = AbelianGroupMorphism(G,H,[x,y],[a,a])
            sage: phi.kernel()
            Group([ f1*f2 ])
        """
        return libgap(self).Kernel()
示例#15
0
    def induct(self, G):
        r"""
        Return the induced character.

        INPUT:

        - ``G`` -- A supergroup of the underlying group of ``self``.

        OUTPUT:

        A :class:`ClassFunction` of ``G`` defined by
        induction. Induction is the adjoint functor to restriction,
        see :meth:`restrict`.

        EXAMPLES::

            sage: G = SymmetricGroup(5)
            sage: H = G.subgroup([(1,2,3), (1,2), (4,5)])
            sage: xi = H.trivial_character(); xi
            Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)]
            sage: xi.induct(G)
            Character of Symmetric group of order 5! as a permutation group
            sage: xi.induct(G).values()
            [10, 4, 2, 1, 1, 0, 0]
        """
        try:
            gapG = G.gap()
        except AttributeError:
            from sage.libs.gap.libgap import libgap
            gapG = libgap(G)
        ind = self._gap_classfunction.InducedClassFunction(gapG)
        return ClassFunction(G, ind)
示例#16
0
    def induct(self, G):
        r"""
        Return the induced character.

        INPUT:

        - ``G`` -- A supergroup of the underlying group of ``self``.

        OUTPUT:

        A :class:`ClassFunction` of ``G`` defined by
        induction. Induction is the adjoint functor to restriction,
        see :meth:`restrict`.

        EXAMPLES::

            sage: G = SymmetricGroup(5)
            sage: H = G.subgroup([(1,2,3), (1,2), (4,5)])
            sage: xi = H.trivial_character(); xi
            Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)]
            sage: xi.induct(G)
            Character of Symmetric group of order 5! as a permutation group
            sage: xi.induct(G).values()
            [10, 4, 2, 1, 1, 0, 0]
        """
        try:
            gapG = G.gap()
        except AttributeError:
            from sage.libs.gap.libgap import libgap
            gapG = libgap(G)
        ind = self._gap_classfunction.InducedClassFunction(gapG)
        return ClassFunction(G, ind)
示例#17
0
    def __init__(self, n=1, R=0):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: H = groups.matrix.Heisenberg(n=2, R=5)
            sage: TestSuite(H).run()  # long time
            sage: H = groups.matrix.Heisenberg(n=2, R=4)
            sage: TestSuite(H).run()  # long time
            sage: H = groups.matrix.Heisenberg(n=3)
            sage: TestSuite(H).run(max_runs=30, skip="_test_elements")  # long time
            sage: H = groups.matrix.Heisenberg(n=2, R=GF(4))
            sage: TestSuite(H).run()  # long time
        """
        def elementary_matrix(i, j, val, MS):
            elm = copy(MS.one())
            elm[i,j] = val
            elm.set_immutable()
            return elm

        self._n = n
        self._ring = R
        # We need the generators of the ring as a commutative additive group
        if self._ring is ZZ:
            ring_gens = [self._ring.one()]
        else:
            if self._ring.cardinality() == self._ring.characteristic():
                ring_gens = [self._ring.one()]
            else:
                # This is overkill, but is the only way to ensure
                #   we get all of the elements
                ring_gens = list(self._ring)

        dim = ZZ(n + 2)
        MS = MatrixSpace(self._ring, dim)
        gens_x = [elementary_matrix(0, j, gen, MS)
                  for j in range(1, dim-1) for gen in ring_gens]
        gens_y = [elementary_matrix(i, dim-1, gen, MS)
                  for i in range(1, dim-1) for gen in ring_gens]
        gen_z = [elementary_matrix(0, dim-1, gen, MS) for gen in ring_gens]
        gens = gens_x + gens_y + gen_z

        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(single_gen) for single_gen in gens]
        gap_group = libgap.Group(gap_gens)

        cat = Groups().FinitelyGenerated()
        if self._ring in Rings().Finite():
            cat = cat.Finite()

        FinitelyGeneratedMatrixGroup_gap.__init__(self, ZZ(dim), self._ring,
                                                  gap_group, category=cat)
示例#18
0
    def _libgap_(self):
        r"""
        TESTS::

            sage: F.<a,b,c> = AbelianGroup([7,8,9])
            sage: libgap(a**2 * c) * libgap(b * c**2)
            f1^2*f2*f6
        """
        from sage.misc.misc_c import prod
        from sage.libs.gap.libgap import libgap
        G = libgap(self.parent())
        return prod(g**i
                    for g, i in zip(G.GeneratorsOfGroup(), self._exponents))
示例#19
0
            def __truediv__(self, relators):
                r"""
                Return the quotient group of self by list of relations or relators

                TODO:

                - also accept list of relations as couples of elements,
                  like semigroup quotients do.

                EXAMPLES:

                We define `ZZ^2` as a quotient of the free group
                on two generators::

                    sage: from mygap import mygap
                    sage: F = mygap.FreeGroup("a", "b")
                    sage: a, b = F.group_generators()
                    sage: G = F / [ a * b * a^-1 * b^-1 ]
                    sage: G
                    <fp group of size infinity on the generators [ a, b ]>
                    sage: a, b = G.group_generators()
                    sage: a * b * a^-1 * b^-1
                    a*b*a^-1*b^-1

                Here, equality testing works well::

                    sage: a * b * a^-1 * b^-1 == G.one()
                    True

                We define a Baumslag-Solitar group::

                    sage: a, b = F.group_generators()
                    sage: G = F / [ a * b * a^-1 * b^-2 ]
                    sage: G
                    <fp group of size infinity on the generators [ a, b ]>
                    sage: a, b = G.group_generators()
                    sage: a * b * a^-1 * b^-2
                    a*b*a^-1*b^-2

                Here, equality testing starts an infinite loop where GAP is trying
                to make the rewriting system confluent (a better implementation
                would alternate between making the rewriting system more confluent
                and trying to answer the equality question -- this is a known
                limitation of GAP's implementation of the Knuth-Bendix procedure)::

                    sage: a * b * a^-1 * b^-2 == G.one() # not tested
                """
                return self._wrap(self.gap() /
                                  libgap([x.gap() for x in relators]))
    def _test_structure_coeffs(self, **options):
        """
        Check the structure coefficients against the GAP implementation.

        EXAMPLES::

            sage: L = LieAlgebra(ZZ, cartan_type=['G',2])
            sage: L._test_structure_coeffs()
        """
        tester = self._tester(**options)
        ct = self.cartan_type()

        # Setup the GAP objects
        from sage.libs.gap.libgap import libgap
        L = libgap.SimpleLieAlgebra(ct.letter, ct.n, libgap(self.base_ring()))
        pos_B, neg_B, h_B = libgap.ChevalleyBasis(L)
        gap_p_roots = libgap.PositiveRoots(libgap.RootSystem(L)).sage()
        #E, F, H = libgap.CanonicalGenerators(L)

        # Setup the conversion between the Sage roots and GAP roots.
        #   The GAP roots are given in terms of the weight lattice.
        p_roots = list(ct.root_system().root_lattice().positive_roots_by_height())
        WL = ct.root_system().weight_lattice()
        La = WL.fundamental_weights()
        convert = {WL(root): root for root in p_roots}
        index = {convert[sum(c*La[j+1] for j,c in enumerate(rt))]: i
                 for i, rt in enumerate(gap_p_roots)}

        # Run the check
        basis = self.basis()
        roots = frozenset(p_roots)
        for i,x in enumerate(p_roots):
            for y in p_roots[i+1:]:
                if x + y in roots:
                    c = basis[x].bracket(basis[y]).leading_coefficient()
                    a, b = (x + y).extraspecial_pair()
                    if (x, y) == (a, b): # If it already is an extra special pair
                        tester.assertEqual(pos_B[index[x]] * pos_B[index[y]],
                                           c * pos_B[index[x+y]],
                                           "extra special pair differ for [{}, {}]".format(x, y))
                    else:
                        tester.assertEqual(pos_B[index[x]] * pos_B[index[y]],
                                           c * pos_B[index[x+y]],
                                           "incorrect structure coefficient for [{}, {}]".format(x, y))
                if x - y in roots: # This must be a negative root if it is a root
                    c = basis[x].bracket(basis[-y]).leading_coefficient()
                    tester.assertEqual(pos_B[index[x]] * neg_B[index[y]],
                                       c * neg_B[index[x-y]],
                                       "incorrect structure coefficient for [{}, {}]".format(x, y))
    def _libgap_(self):
        """
        Only works for finite groups.

        EXAMPLES::

            sage: G = AbelianGroup(3,[2,3,4],names="abc"); G
            Multiplicative Abelian group isomorphic to C2 x C3 x C4
            sage: a,b,c = G.gens()
            sage: H = AbelianGroup(2,[2,3],names="xy"); H
            Multiplicative Abelian group isomorphic to C2 x C3
            sage: x,y = H.gens()
            sage: phi = AbelianGroupMorphism(H,G,[x,y],[a,b])
            sage: libgap(phi)
            [ f1, f2 ] -> [ f1, f2 ]
            sage: phi = AbelianGroupMorphism(H,G,[x,y],[a*c**2,b])
            sage: libgap(phi)
            [ f1, f2 ] -> [ f1*f4, f2 ]
        """
        G  = libgap(self.domain())
        H  = libgap(self.codomain())
        in_G = [libgap(g) for g in self.domaingens]
        in_H = [libgap(h) for h in self.codomaingens]
        return G.GroupHomomorphismByImages(H, in_G, in_H)
            def __truediv__(self, relators):
                r"""
                Return the quotient group of self by list of relations or relators

                TODO:

                - also accept list of relations as couples of elements,
                  like semigroup quotients do.

                EXAMPLES:

                We define `ZZ^2` as a quotient of the free group
                on two generators::

                    sage: from mygap import mygap
                    sage: F = mygap.FreeGroup("a", "b")
                    sage: a, b = F.group_generators()
                    sage: G = F / [ a * b * a^-1 * b^-1 ]
                    sage: G
                    <fp group of size infinity on the generators [ a, b ]>
                    sage: a, b = G.group_generators()
                    sage: a * b * a^-1 * b^-1
                    a*b*a^-1*b^-1

                Here, equality testing works well::

                    sage: a * b * a^-1 * b^-1 == G.one()
                    True

                We define a Baumslag-Solitar group::

                    sage: a, b = F.group_generators()
                    sage: G = F / [ a * b * a^-1 * b^-2 ]
                    sage: G
                    <fp group of size infinity on the generators [ a, b ]>
                    sage: a, b = G.group_generators()
                    sage: a * b * a^-1 * b^-2
                    a*b*a^-1*b^-2

                Here, equality testing starts an infinite loop where GAP is trying
                to make the rewriting system confluent (a better implementation
                would alternate between making the rewriting system more confluent
                and trying to answer the equality question -- this is a known
                limitation of GAP's implementation of the Knuth-Bendix procedure)::

                    sage: a * b * a^-1 * b^-2 == G.one() # not tested
                """
                return self._wrap( self.gap() / libgap([x.gap() for x in relators]) )
示例#23
0
    def __init__(self,
                 degree,
                 base_ring,
                 gens,
                 invariant_bilinear_form,
                 category=None,
                 check=True,
                 invariant_submodule=None,
                 invariant_quotient_module=None):
        r"""
        Create this orthogonal group from the input.

        TESTS::

            sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries
            sage: bil = Matrix(ZZ,2,[3,2,2,3])
            sage: gens = [-Matrix(ZZ,2,[0,1,1,0])]
            sage: cat = Groups().Finite()
            sage: O = GroupOfIsometries(2, ZZ, gens, bil, category=cat)
            sage: TestSuite(O).run()
        """
        from copy import copy
        G = copy(invariant_bilinear_form)
        G.set_immutable()
        self._invariant_bilinear_form = G
        self._invariant_submodule = invariant_submodule
        self._invariant_quotient_module = invariant_quotient_module
        if check:
            I = invariant_submodule
            Q = invariant_quotient_module
            for f in gens:
                self._check_matrix(f)
                if (not I is None) and I * f != I:
                    raise ValueError("the submodule is not preserved")
                if not Q is None and (Q.W() != Q.W() * f
                                      or Q.V() * f != Q.V()):
                    raise ValueError("the quotient module is not preserved")
        if len(gens) == 0:  # handle the trivial group
            gens = [G.parent().identity_matrix()]
        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)
        FinitelyGeneratedMatrixGroup_gap.__init__(self,
                                                  degree,
                                                  base_ring,
                                                  gap_group,
                                                  category=category)
示例#24
0
    def module_composition_factors(self, algorithm=None):
        r"""
        Return a list of triples consisting of [base field, dimension,
        irreducibility], for each of the Meataxe composition factors
        modules. The ``algorithm="verbose"`` option returns more information,
        but in Meataxe notation.

        EXAMPLES::

            sage: F = GF(3); MS = MatrixSpace(F,4,4)
            sage: M = MS(0)
            sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1
            sage: G = MatrixGroup([M])
            sage: G.module_composition_factors()
            [(Finite Field of size 3, 1, True),
             (Finite Field of size 3, 1, True),
             (Finite Field of size 3, 2, True)]
            sage: F = GF(7); MS = MatrixSpace(F,2,2)
            sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
            sage: G = MatrixGroup(gens)
            sage: G.module_composition_factors()
            [(Finite Field of size 7, 2, True)]

        Type ``G.module_composition_factors(algorithm='verbose')`` to get a
        more verbose version.

        For more on MeatAxe notation, see
        https://www.gap-system.org/Manuals/doc/ref/chap69.html
        """
        from sage.libs.gap.libgap import libgap
        F = self.base_ring()
        if not F.is_finite():
            raise NotImplementedError("Base ring must be finite.")
        n = self.degree()
        MS = MatrixSpace(F, n, n)
        mats = [MS(g.matrix()) for g in self.gens()]
        # initializing list of mats by which the gens act on self
        mats_gap = libgap(mats)
        M = mats_gap.GModuleByMats(F)
        compo = libgap.function_factory('MTX.CompositionFactors')
        MCFs = compo(M)
        if algorithm == "verbose":
            print(str(MCFs) + "\n")
        return sorted((MCF['field'].sage(),
                       MCF['dimension'].sage(),
                       MCF['IsIrreducible'].sage()) for MCF in MCFs)
示例#25
0
def to_libgap(x):
    """
    Helper to convert ``x`` to a LibGAP matrix or matrix group
    element.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.morphism import to_libgap
        sage: to_libgap(GL(2,3).gen(0))
        [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]
        sage: to_libgap(matrix(QQ, [[1,2],[3,4]]))
        [ [ 1, 2 ], [ 3, 4 ] ]
    """
    try:
        return x.gap()
    except AttributeError:
        from sage.libs.gap.libgap import libgap
        return libgap(x)
示例#26
0
    def orbits(G, L):
        r"""
        Return the orbits of `L` under `G`.

        INPUT:

        - ``G`` -- an fqf_orthognal group
        - ``L`` -- a list of tuples of elements of the domain of ``G``

        A list of orbit representatives of `L`
        """
        D = G.invariant_form()
        A = G.domain()
        L = libgap([[A(g).gap() for g in f] for f in L])
        orb = G.gap().Orbits(L,libgap.OnTuples)
        orb = [g[0] for g in orb]
        orb = [[D.linear_combination_of_smith_form_gens(A(g).exponents()) for g in f] for f in orb]
        return orb
示例#27
0
def to_libgap(x):
    """
    Helper to convert ``x`` to a LibGAP matrix or matrix group
    element.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.morphism import to_libgap
        sage: to_libgap(GL(2,3).gen(0))
        [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]
        sage: to_libgap(matrix(QQ, [[1,2],[3,4]]))
        [ [ 1, 2 ], [ 3, 4 ] ]
    """
    try:
        return x.gap()
    except AttributeError:
        from sage.libs.gap.libgap import libgap
        return libgap(x)
示例#28
0
    def __init__(self, parent, M, check=True, convert=True):
        r"""
        Element of a matrix group over a generic ring.

        The group elements are implemented as Sage matrices.

        INPUT:

        - ``M`` -- a matrix.

        - ``parent`` -- the parent.

        - ``check`` -- bool (default: ``True``). If true does some
          type checking.

        - ``convert`` -- bool (default: ``True``). If true convert
          ``M`` to the right matrix space.

        TESTS::

            sage: MS = MatrixSpace(GF(3),2,2)
            sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]]))
            sage: G.gen(0)
            [1 0]
            [0 1]
            sage: g = G.random_element()
            sage: TestSuite(g).run()
        """
        if isinstance(M, GapElement):
            ElementLibGAP.__init__(self, parent, M)
            return
        if convert:
            M = parent.matrix_space()(M)
        from sage.libs.gap.libgap import libgap

        M_gap = libgap(M)
        if check:
            if not is_Matrix(M):
                raise TypeError("M must be a matrix")
            if M.parent() is not parent.matrix_space():
                raise TypeError("M must be a in the matrix space of the group")
            parent._check_matrix(M, M_gap)
        ElementLibGAP.__init__(self, parent, M_gap)
    def norm_of_galois_extension(self):
        r"""
        Returns the norm as a Galois extension of `\QQ`, which is
        given by the product of all galois_conjugates.

        EXAMPLES::

            sage: E(3).norm_of_galois_extension()
            1
            sage: E(6).norm_of_galois_extension()
            1
            sage: (E(2) + E(3)).norm_of_galois_extension()
            3
            sage: parent(_)
            Integer Ring
        """
        obj = self._obj
        k = obj.Conductor().sage()
        return libgap.Product(libgap([obj.GaloisCyc(i) for i in range(k) if k.gcd(i) == 1])).sage()
    def norm_of_galois_extension(self):
        r"""
        Return the norm as a Galois extension of `\QQ`, which is
        given by the product of all galois_conjugates.

        EXAMPLES::

            sage: E(3).norm_of_galois_extension()
            1
            sage: E(6).norm_of_galois_extension()
            1
            sage: (E(2) + E(3)).norm_of_galois_extension()
            3
            sage: parent(_)
            Integer Ring
        """
        obj = self._obj
        k = obj.Conductor().sage()
        return libgap.Product(libgap([obj.GaloisCyc(i) for i in range(k) if k.gcd(i) == 1])).sage()
示例#31
0
    def __init__(self, degree, base_ring,
                 gens, invariant_bilinear_form,
                 category=None, check=True,
                 invariant_submodule=None,
                 invariant_quotient_module=None):
        r"""
        Create this orthogonal group from the input.

        TESTS::

            sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries
            sage: bil = Matrix(ZZ,2,[3,2,2,3])
            sage: gens = [-Matrix(ZZ,2,[0,1,1,0])]
            sage: cat = Groups().Finite()
            sage: O = GroupOfIsometries(2, ZZ, gens, bil, category=cat)
            sage: TestSuite(O).run()
        """
        from copy import copy
        G = copy(invariant_bilinear_form)
        G.set_immutable()
        self._invariant_bilinear_form = G
        self._invariant_submodule = invariant_submodule
        self._invariant_quotient_module = invariant_quotient_module
        if check:
            I = invariant_submodule
            Q = invariant_quotient_module
            for f in gens:
                self._check_matrix(f)
                if (not I is None) and I*f != I:
                    raise ValueError("the submodule is not preserved")
                if not Q is None and (Q.W() != Q.W()*f or Q.V()*f != Q.V()):
                    raise ValueError("the quotient module is not preserved")
        if len(gens) == 0:    # handle the trivial group
            gens = [G.parent().identity_matrix()]
        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)
        FinitelyGeneratedMatrixGroup_gap.__init__(self,
                                                  degree,
                                                  base_ring,
                                                  gap_group,
                                                  category=category)
示例#32
0
    def __init__(self, M, parent, check=True, convert=True):
        r"""
        Element of a matrix group over a generic ring.

        The group elements are implemented as Sage matrices.

        INPUT:

        - ``M`` -- a matrix.

        - ``parent`` -- the parent.

        - ``check`` -- bool (default: ``True``). If true does some
          type checking.

        - ``convert`` -- bool (default: ``True``). If true convert
          ``M`` to the right matrix space.

        TESTS::

            sage: MS = MatrixSpace(GF(3),2,2)
            sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]]))
            sage: G.gen(0)
            [1 0]
            [0 1]
            sage: g = G.random_element()
            sage: TestSuite(g).run()
        """
        if isinstance(M, GapElement):
            ElementLibGAP.__init__(self, M, parent)
            return
        if convert:
            M = parent.matrix_space()(M)
        from sage.libs.gap.libgap import libgap
        M_gap = libgap(M)
        if check:
            if not is_Matrix(M):
                raise TypeError('M must be a matrix')
            if M.parent() is not parent.matrix_space():
                raise TypeError('M must be a in the matrix space of the group')
            parent._check_matrix(M, M_gap)
        ElementLibGAP.__init__(self, M_gap, parent)
示例#33
0
 def __call__(self, *args):
     return GAP(libgap(*args))
 def __call__(self, *args):
     return GAP(libgap(*args))
示例#35
0
    def _element_constructor_(self, elt):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: UCF(3)
            3
            sage: UCF(3/2)
            3/2

            sage: C = CyclotomicField(13)
            sage: UCF(C.gen())
            E(13)
            sage: UCF(C.gen() - 3*C.gen()**2 + 5*C.gen()**5)
            E(13) - 3*E(13)^2 + 5*E(13)^5

            sage: C = CyclotomicField(12)
            sage: zeta12 = C.gen()
            sage: a = UCF(zeta12 - 3* zeta12**2)
            sage: a
            -E(12)^7 + 3*E(12)^8
            sage: C(_) == a
            True

            sage: UCF('[[0, 1], [0, 2]]')
            Traceback (most recent call last):
            ...
            TypeError: [ [ 0, 1 ], [ 0, 2 ] ]
            of type <type 'sage.libs.gap.element.GapElement_List'> not valid
            to initialize an element of the universal cyclotomic field

        Some conversions from symbolic functions are possible::

            sage: UCF = UniversalCyclotomicField()
            sage: [UCF(sin(pi/k, hold=True)) for k in range(1,10)]
            [0,
             1,
             -1/2*E(12)^7 + 1/2*E(12)^11,
             1/2*E(8) - 1/2*E(8)^3,
             -1/2*E(20)^13 + 1/2*E(20)^17,
             1/2,
             -1/2*E(28)^19 + 1/2*E(28)^23,
             1/2*E(16)^3 - 1/2*E(16)^5,
             -1/2*E(36)^25 + 1/2*E(36)^29]
            sage: [UCF(cos(pi/k, hold=True)) for k in range(1,10)]
            [-1,
             0,
             1/2,
             1/2*E(8) - 1/2*E(8)^3,
             -1/2*E(5)^2 - 1/2*E(5)^3,
             -1/2*E(12)^7 + 1/2*E(12)^11,
             -1/2*E(7)^3 - 1/2*E(7)^4,
             1/2*E(16) - 1/2*E(16)^7,
             -1/2*E(9)^4 - 1/2*E(9)^5]

        .. TODO::

            Implement conversion from QQbar (and as a consequence from the
            symbolic ring)
        """
        elt = py_scalar_to_element(elt)

        if isinstance(elt, (Integer, Rational)):
            return self.element_class(self, libgap(elt))
        elif isinstance(
                elt,
            (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)):
            return self.element_class(self, elt)
        elif not elt:
            return self.zero()

        obj = None
        if isinstance(elt, gap.GapElement):
            obj = libgap(elt)
        elif isinstance(elt, gap3.GAP3Element):
            obj = libgap.eval(str(elt))
        elif isinstance(elt, str):
            obj = libgap.eval(elt)
        if obj is not None:
            if not isinstance(obj, (GapElement_Integer, GapElement_Rational,
                                    GapElement_Cyclotomic)):
                raise TypeError(
                    "{} of type {} not valid to initialize an element of the universal cyclotomic field"
                    .format(obj, type(obj)))
            return self.element_class(self, obj)

        # late import to avoid slowing down the above conversions
        from sage.rings.number_field.number_field_element import NumberFieldElement
        from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField
        P = parent(elt)
        if isinstance(elt, NumberFieldElement) and isinstance(
                P, NumberField_cyclotomic):
            n = P.gen().multiplicative_order()
            elt = CyclotomicField(n)(elt)
            return sum(c * self.gen(n, i)
                       for i, c in enumerate(elt._coefficients()))

        if hasattr(elt, '_algebraic_'):
            return elt._algebraic_(self)

        raise TypeError(
            "{} of type {} not valid to initialize an element of the universal cyclotomic field"
            .format(elt, type(elt)))
    def _element_constructor_(self, elt):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: UCF(3)
            3
            sage: UCF(3/2)
            3/2

            sage: C = CyclotomicField(13)
            sage: UCF(C.gen())
            E(13)
            sage: UCF(C.gen() - 3*C.gen()**2 + 5*C.gen()**5)
            E(13) - 3*E(13)^2 + 5*E(13)^5

            sage: C = CyclotomicField(12)
            sage: zeta12 = C.gen()
            sage: a = UCF(zeta12 - 3* zeta12**2)
            sage: a
            -E(12)^7 + 3*E(12)^8
            sage: C(_) == a
            True

            sage: UCF('[[0, 1], [0, 2]]')
            Traceback (most recent call last):
            ...
            TypeError: [ [ 0, 1 ], [ 0, 2 ] ] of type <type
            'sage.libs.gap.element.GapElement_List'> not valid to initialize an
            element of the universal cyclotomic field

        .. TODO::

            Implement conversion from QQbar (and as a consequence from the
            symbolic ring)
        """
        elt = py_scalar_to_element(elt)

        if isinstance(elt, (Integer, Rational)):
            return self.element_class(self, libgap(elt))
        elif isinstance(elt, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)):
            return self.element_class(self, elt)
        elif not elt:
            return self.zero()

        obj = None
        if isinstance(elt, gap.GapElement):
            obj = libgap(elt)
        elif isinstance(elt, gap3.GAP3Element):
            obj = libgap.eval(str(elt))
        elif isinstance(elt, str):
            obj = libgap.eval(elt)
        if obj is not None:
            if not isinstance(obj, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)):
                raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(obj, type(obj)))
            return self.element_class(self, obj)

        # late import to avoid slowing down the above conversions
        from sage.rings.number_field.number_field_element import NumberFieldElement
        from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField
        P = parent(elt)
        if isinstance(elt, NumberFieldElement) and isinstance(P, NumberField_cyclotomic):
            n = P.gen().multiplicative_order()
            elt = CyclotomicField(n)(elt)
            coeffs = elt._coefficients()
            return sum(c * self.gen(n,i) for i,c in enumerate(elt._coefficients()))
        else:
            raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(elt, type(elt)))
示例#37
0
def MatrixGroup(*gens, **kwds):
    r"""
    Return the matrix group with given generators.

    INPUT:

    - ``*gens`` -- matrices, or a single list/tuple/iterable of
      matrices, or a matrix group.

    - ``check`` -- boolean keyword argument (optional, default:
      ``True``). Whether to check that each matrix is invertible.

    EXAMPLES::

        sage: F = GF(5)
        sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 5 with 2 generators (
        [1 2]  [1 1]
        [4 1], [0 1]
        )

    In the second example, the generators are a matrix over
    `\ZZ`, a matrix over a finite field, and the integer
    `2`. Sage determines that they both canonically map to
    matrices over the finite field, so creates that matrix group
    there::

        sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 7 with 3 generators (
        [1 2]  [1 1]  [2 0]
        [6 1], [0 1], [0 2]
        )

    Each generator must be invertible::

        sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix

        sage: F = GF(5); MS = MatrixSpace(F,2,2)
        sage: MatrixGroup([MS.0])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix
        sage: MatrixGroup([MS.0], check=False)  # works formally but is mathematical nonsense
        Matrix group over Finite Field of size 5 with 1 generators (
        [1 0]
        [0 0]
        )

    Some groups are not supported, or do not have much functionality
    implemented::

        sage: G = SL(0, QQ)
        Traceback (most recent call last):
        ...
        ValueError: the degree must be at least 1

        sage: SL2C = SL(2, CC);  SL2C
        Special Linear Group of degree 2 over Complex Field with 53 bits of precision
        sage: SL2C.gens()
        Traceback (most recent call last):
        ...
        AttributeError: 'LinearMatrixGroup_generic_with_category' object has no attribute 'gens'
    """
    if isinstance(gens[-1], dict):  # hack for unpickling
        kwds.update(gens[-1])
        gens = gens[:-1]
    check = kwds.get('check', True)
    if len(gens) == 1:
        if isinstance(gens[0], (list, tuple)):
            gens = list(gens[0])
        else:
            try:
                gens = [g.matrix() for g in gens[0]]
            except AttributeError:
                pass
    if len(gens) == 0:
        raise ValueError('need at least one generator')
    gens = normalize_square_matrices(gens)
    if check and any(not g.is_invertible() for g in gens):
        raise ValueError('each generator must be an invertible matrix')
    MS = gens.universe()
    base_ring = MS.base_ring()
    degree = ZZ(MS.ncols())  # == MS.nrows()
    from sage.libs.gap.libgap import libgap
    try:
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)
        return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group)
    except (TypeError, ValueError):
        return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens)
def isotypic_projection_matrix(G, d, chi, deg, conj_mats=None):
    r"""
    Return an isotypic projection matrix

    INPUT:

    - ``G`` -- a permutation group

    - ``d`` -- (integer) the domain of the group is `\{1, 2, \ldots, d\}`

    - ``chi`` -- (tuple) real or complex character

    - ``deg`` -- (integer) degree of the character

    Recall the formula for the projection as given in Theorem 8 in [Ser]_. If
    `G` is a permutation group, then
    
    .. MATH::
    
        \pi_\chi = \sum_{g \in G} \overline_{\chi(g)} g

    REFERENCES::

    .. [Ser] J.-P. Serre, "Représentation des groupes finis."

    EXAMPLES::

        sage: from surface_dynamics.misc.group_representation import real_characters, isotypic_projection_matrix
        sage: G = AlternatingGroup(5)
        sage: T,deg = real_characters(G)
        sage: isotypic_projection_matrix(G, 5, T[0], deg[0])
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        sage: isotypic_projection_matrix(G, 5, T[1], deg[1])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        sage: isotypic_projection_matrix(G, 5, T[2], deg[2])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        sage: isotypic_projection_matrix(G, 5, T[3], deg[3])
        [ 4/5 -1/5 -1/5 -1/5 -1/5]
        [-1/5  4/5 -1/5 -1/5 -1/5]
        [-1/5 -1/5  4/5 -1/5 -1/5]
        [-1/5 -1/5 -1/5  4/5 -1/5]
        [-1/5 -1/5 -1/5 -1/5  4/5]
        sage: isotypic_projection_matrix(G, 5, T[4], deg[4])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]

        sage: sum(isotypic_projection_matrix(G, 5, T[i], deg[i]) for i in range(5)).is_one()
        True
    """
    from sage.matrix.special import zero_matrix
    res = zero_matrix(d)

    Ggap = libgap(G)

    for t,cl in enumerate(Ggap.ConjugacyClasses()):
        if conj_mats is None:
            m = conjugacy_class_matrix(cl, d)
        else:
            m = conj_mats[t]
        res += chi[t] * conjugacy_class_matrix(cl,d)

    return deg / G.cardinality() * res
示例#39
0
def MatrixGroup(*gens, **kwds):
    r"""
    Return the matrix group with given generators.

    INPUT:

    - ``*gens`` -- matrices, or a single list/tuple/iterable of
      matrices, or a matrix group.

    - ``check`` -- boolean keyword argument (optional, default:
      ``True``). Whether to check that each matrix is invertible.

    EXAMPLES::

        sage: F = GF(5)
        sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 5 with 2 generators (
        [1 2]  [1 1]
        [4 1], [0 1]
        )

    In the second example, the generators are a matrix over
    `\ZZ`, a matrix over a finite field, and the integer
    `2`. Sage determines that they both canonically map to
    matrices over the finite field, so creates that matrix group
    there::

        sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 7 with 3 generators (
        [1 2]  [1 1]  [2 0]
        [6 1], [0 1], [0 2]
        )

    Each generator must be invertible::

        sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix

        sage: F = GF(5); MS = MatrixSpace(F,2,2)
        sage: MatrixGroup([MS.0])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix
        sage: MatrixGroup([MS.0], check=False)  # works formally but is mathematical nonsense
        Matrix group over Finite Field of size 5 with 1 generators (
        [1 0]
        [0 0]
        )

    Some groups are not supported, or do not have much functionality
    implemented::

        sage: G = SL(0, QQ)
        Traceback (most recent call last):
        ...
        ValueError: the degree must be at least 1

        sage: SL2C = SL(2, CC);  SL2C
        Special Linear Group of degree 2 over Complex Field with 53 bits of precision
        sage: SL2C.gens()
        Traceback (most recent call last):
        ...
        AttributeError: 'LinearMatrixGroup_generic_with_category' object has no attribute 'gens'
    """
    if isinstance(gens[-1], dict):   # hack for unpickling
        kwds.update(gens[-1])
        gens = gens[:-1]
    check = kwds.get('check', True)
    if len(gens) == 1:
        if isinstance(gens[0], (list, tuple)):
            gens = list(gens[0])
        else:
            try:
                gens = [g.matrix() for g in gens[0]]
            except AttributeError:
                pass
    if len(gens) == 0:
        raise ValueError('need at least one generator')
    gens = normalize_square_matrices(gens)
    if check and any(not g.is_invertible() for g in gens):
        raise ValueError('each generator must be an invertible matrix')
    MS = gens.universe()
    base_ring = MS.base_ring()
    degree = ZZ(MS.ncols())   # == MS.nrows()
    from sage.libs.gap.libgap import libgap
    try:
        gap_gens = [libgap(matrix_gen) for matrix_gen in gens]
        gap_group = libgap.Group(gap_gens)
        return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group)
    except (TypeError, ValueError):
        return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens)
def real_characters(G):
    r"""
    Return a pair ``(table of characters, character degrees)`` for the
    group ``G``.

    OUPUT:

    - 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 xrange(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 xrange(n)))

    return (real_T, real_degrees)
    def _element_constructor_(self, elt):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: UCF(3)
            3
            sage: UCF(3/2)
            3/2

            sage: C = CyclotomicField(13)
            sage: UCF(C.gen())
            E(13)
            sage: UCF(C.gen() - 3*C.gen()**2 + 5*C.gen()**5)
            E(13) - 3*E(13)^2 + 5*E(13)^5

            sage: C = CyclotomicField(12)
            sage: zeta12 = C.gen()
            sage: a = UCF(zeta12 - 3* zeta12**2)
            sage: a
            -E(12)^7 + 3*E(12)^8
            sage: C(_) == a
            True

            sage: UCF('[[0, 1], [0, 2]]')
            Traceback (most recent call last):
            ...
            TypeError: [ [ 0, 1 ], [ 0, 2 ] ] of type <type
            'sage.libs.gap.element.GapElement_List'> not valid to initialize an
            element of the universal cyclotomic field

        .. TODO::

            Implement conversion from QQbar (and as a consequence from the
            symbolic ring)
        """
        elt = py_scalar_to_element(elt)

        if isinstance(elt, (Integer, Rational)):
            return self.element_class(self, libgap(elt))
        elif isinstance(elt, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)):
            return self.element_class(self, elt)
        elif not elt:
            return self.zero()

        obj = None
        if isinstance(elt, gap.GapElement):
            obj = libgap(elt)
        elif isinstance(elt, gap3.GAP3Element):
            obj = libgap.eval(str(elt))
        elif isinstance(elt, str):
            obj = libgap.eval(elt)
        if obj is not None:
            if not isinstance(obj, (GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic)):
                raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(obj, type(obj)))
            return self.element_class(self, obj)

        # late import to avoid slowing down the above conversions
        from sage.rings.number_field.number_field_element import NumberFieldElement
        from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField
        P = parent(elt)
        if isinstance(elt, NumberFieldElement) and isinstance(P, NumberField_cyclotomic):
            n = P.gen().multiplicative_order()
            elt = CyclotomicField(n)(elt)
            return sum(c * self.gen(n, i)
                       for i, c in enumerate(elt._coefficients()))
        else:
            raise TypeError("{} of type {} not valid to initialize an element of the universal cyclotomic field".format(elt, type(elt)))
 def __truediv__(self, relations):
     return self._wrap(self.gap() /
                       libgap([[x.gap(), y.gap()]
                               for x, y in relations]))
def isotypic_projection_matrix(G, d, chi, deg, conj_mats=None, floating_point=False):
    r"""
    Return an isotypic projection matrix

    INPUT:

    - ``G`` -- a permutation group

    - ``d`` -- (integer) the domain of the group is `\{1, 2, \ldots, d\}`

    - ``chi`` -- (tuple) real or complex character

    - ``deg`` -- (integer) degree of the character

    - ``conj_mats`` -- (optional list) matrices of the conjugacy classes

    - ``floating_point`` -- whether to return matrices with floating point entries instead
                   of elements in the cyclotomic field

    Recall the formula for the projection as given in Theorem 8 in [Ser67]_. If
    `G` is a permutation group, then

    .. MATH::

        \pi_\chi = \sum_{g \in G} \overline_{\chi(g)} g

    EXAMPLES::

        sage: from surface_dynamics.misc.group_representation import real_characters, isotypic_projection_matrix
        sage: G = AlternatingGroup(5)
        sage: T,deg = real_characters(G)
        sage: isotypic_projection_matrix(G, 5, T[0], deg[0])
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        [1/5 1/5 1/5 1/5 1/5]
        sage: isotypic_projection_matrix(G, 5, T[1], deg[1])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        sage: isotypic_projection_matrix(G, 5, T[2], deg[2])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        sage: isotypic_projection_matrix(G, 5, T[3], deg[3])
        [ 4/5 -1/5 -1/5 -1/5 -1/5]
        [-1/5  4/5 -1/5 -1/5 -1/5]
        [-1/5 -1/5  4/5 -1/5 -1/5]
        [-1/5 -1/5 -1/5  4/5 -1/5]
        [-1/5 -1/5 -1/5 -1/5  4/5]
        sage: isotypic_projection_matrix(G, 5, T[3], deg[3], floating_point=True)
        array([[ 0.8, -0.2, -0.2, -0.2, -0.2],
               [-0.2,  0.8, -0.2, -0.2, -0.2],
               [-0.2, -0.2,  0.8, -0.2, -0.2],
               [-0.2, -0.2, -0.2,  0.8, -0.2],
               [-0.2, -0.2, -0.2, -0.2,  0.8]])
        sage: isotypic_projection_matrix(G, 5, T[4], deg[4])
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]
        [0 0 0 0 0]

        sage: sum(isotypic_projection_matrix(G, 5, T[i], deg[i]) for i in range(5)).is_one()
        True
    """
    from sage.matrix.special import zero_matrix
    res = zero_matrix(d)

    Ggap = libgap(G)

    for t, cl in enumerate(Ggap.ConjugacyClasses()):
        if conj_mats is None:
            m = conjugacy_class_matrix(cl, d)
        else:
            m = conj_mats[t]
        if floating_point:
            res += np.float64(chi[t]) * m.numpy()
        else:
            res += chi[t] * m

    if floating_point:
            return int(deg) * res / int(G.cardinality())
    else:
            return deg * res / G.cardinality()
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)