Ejemplo n.º 1
0
r"""
Additive groups
"""
#*****************************************************************************
#  Copyright (C) 2013 Nicolas M. Thiery <nthiery at users.sf.net>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#                  http://www.gnu.org/licenses/
#******************************************************************************

from sage.misc.lazy_import import LazyImport
from sage.categories.category_with_axiom import CategoryWithAxiom_singleton, CategoryWithAxiom
from sage.categories.algebra_functor import AlgebrasCategory
from sage.categories.additive_monoids import AdditiveMonoids
Groups = LazyImport('sage.categories.groups', 'Groups', at_startup=True)


class AdditiveGroups(CategoryWithAxiom_singleton):
    r"""
    The category of additive groups.

    An *additive group* is a set with an internal binary operation `+` which
    is associative, admits a zero, and where every element can be negated.

    EXAMPLES::

        sage: from sage.categories.additive_groups import AdditiveGroups
        sage: from sage.categories.additive_monoids import AdditiveMonoids
        sage: AdditiveGroups()
        Category of additive groups
        sage: AdditiveGroups().super_categories()
Ejemplo n.º 2
0
class WeylGroups(Category_singleton):
    r"""
    The category of Weyl groups

    See the :wikipedia:`Wikipedia page of Weyl Groups <Weyl_group>`.

    EXAMPLES::

        sage: WeylGroups()
        Category of weyl groups
        sage: WeylGroups().super_categories()
        [Category of coxeter groups]

    Here are some examples::

        sage: WeylGroups().example()            # todo: not implemented
        sage: FiniteWeylGroups().example()
        The symmetric group on {0, ..., 3}
        sage: AffineWeylGroups().example()      # todo: not implemented
        sage: WeylGroup(["B", 3])
        Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space)

    This one will eventually be also in this category::

        sage: SymmetricGroup(4)
        Symmetric group of order 4! as a permutation group

    TESTS::

        sage: C = WeylGroups()
        sage: TestSuite(C).run()
    """
    def super_categories(self):
        r"""
        EXAMPLES::

            sage: WeylGroups().super_categories()
            [Category of coxeter groups]
        """
        return [CoxeterGroups()]

    def additional_structure(self):
        r"""
        Return  ``None``.

        Indeed, the category of Weyl groups defines no additional
        structure: Weyl groups are a special class of Coxeter groups.

        .. SEEALSO:: :meth:`Category.additional_structure`

        .. TODO:: Should this category be a :class:`CategoryWithAxiom`?

        EXAMPLES::

            sage: WeylGroups().additional_structure()
        """
        return None

    Finite = LazyImport('sage.categories.finite_weyl_groups',
                        'FiniteWeylGroups')

    class ParentMethods:
        def pieri_factors(self, *args, **keywords):
            r"""
            Returns the set of Pieri factors in this Weyl group.

            For any type, the set of Pieri factors forms a lower ideal
            in Bruhat order, generated by all the conjugates of some
            special element of the Weyl group. In type `A_n`, this
            special element is `s_n\cdots s_1`, and the conjugates are
            obtained by rotating around this reduced word.

            These are used to compute Stanley symmetric functions.

            .. SEEALSO::

                * :meth:`WeylGroups.ElementMethods.stanley_symmetric_function`
                * :mod:`sage.combinat.root_system.pieri_factors`

            EXAMPLES::

                sage: W = WeylGroup(['A',5,1])
                sage: PF = W.pieri_factors()
                sage: PF.cardinality()
                63

                sage: W = WeylGroup(['B',3])
                sage: PF = W.pieri_factors()
                sage: [w.reduced_word() for w in PF]
                [[1, 2, 3, 2, 1], [1, 2, 3, 2], [2, 3, 2], [2, 3], [3, 1, 2, 1], [1, 2, 1], [2], [1, 2], [1], [], [2, 1], [3, 2, 1], [3, 1], [2, 3, 2, 1], [3], [3, 2], [1, 2, 3], [1, 2, 3, 1], [3, 1, 2], [2, 3, 1]]

                sage: W = WeylGroup(['C',4,1])
                sage: PF = W.pieri_factors()
                sage: W.from_reduced_word([3,2,0]) in PF
                True
            """
            # Do not remove this line which makes sure the pieri factor
            # code is properly inserted inside the Cartan Types
            import sage.combinat.root_system.pieri_factors
            ct = self.cartan_type()
            if hasattr(ct, "PieriFactors"):
                return ct.PieriFactors(self, *args, **keywords)
            raise NotImplementedError("Pieri factors for type {}".format(ct))

        @cached_method
        def quantum_bruhat_graph(self, index_set=()):
            r"""
            Returns the quantum Bruhat graph of the quotient of the Weyl group by a parabolic subgroup `W_J`.

            INPUT:

            - ``index_set`` -- a tuple `J` of nodes of the Dynkin diagram (default: ())

            By default, the value for ``index_set`` indicates that the subgroup is trivial and the quotient is the full Weyl group.

            EXAMPLES::

                sage: W = WeylGroup(['A',3], prefix="s")
                sage: g = W.quantum_bruhat_graph((1,3))
                sage: g
                Parabolic Quantum Bruhat Graph of Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) for nodes (1, 3): Digraph on 6 vertices
                sage: g.vertices()
                [s2*s3*s1*s2, s3*s1*s2, s1*s2, s3*s2, s2, 1]
                sage: g.edges()
                [(s2*s3*s1*s2, s2, alpha[2]), (s3*s1*s2, s2*s3*s1*s2, alpha[1] + alpha[2] + alpha[3]),
                (s3*s1*s2, 1, alpha[2]), (s1*s2, s3*s1*s2, alpha[2] + alpha[3]),
                (s3*s2, s3*s1*s2, alpha[1] + alpha[2]), (s2, s1*s2, alpha[1] + alpha[2]),
                (s2, s3*s2, alpha[2] + alpha[3]), (1, s2, alpha[2])]
                sage: W = WeylGroup(['A',3,1], prefix="s")
                sage: g = W.quantum_bruhat_graph()
                Traceback (most recent call last):
                ...
                ValueError: The Cartan type ['A', 3, 1] is not finite
            """
            if not self.cartan_type().is_finite():
                raise ValueError("The Cartan type {} is not finite".format(
                    self.cartan_type()))
            from sage.graphs.digraph import DiGraph
            WP = [x for x in self if x == x.coset_representative(index_set)]
            return DiGraph(
                [[x, i[0], i[1]] for x in WP
                 for i in x.quantum_bruhat_successors(index_set, roots=True)],
                name="Parabolic Quantum Bruhat Graph of %s for nodes %s" %
                (self, index_set))

    class ElementMethods:
        def is_pieri_factor(self):
            r"""
            Returns whether ``self`` is a Pieri factor, as used for
            computing Stanley symmetric functions.

            .. SEEALSO::

                * :meth:`stanley_symmetric_function`
                * :meth:`WeylGroups.ParentMethods.pieri_factors`

            EXAMPLES::

                sage: W = WeylGroup(['A',5,1])
                sage: W.from_reduced_word([3,2,5]).is_pieri_factor()
                True
                sage: W.from_reduced_word([3,2,4,5]).is_pieri_factor()
                False

                sage: W = WeylGroup(['C',4,1])
                sage: W.from_reduced_word([0,2,1]).is_pieri_factor()
                True
                sage: W.from_reduced_word([0,2,1,0]).is_pieri_factor()
                False

                sage: W = WeylGroup(['B',3])
                sage: W.from_reduced_word([3,2,3]).is_pieri_factor()
                False
                sage: W.from_reduced_word([2,1,2]).is_pieri_factor()
                True
            """

            return self in self.parent().pieri_factors()

        def left_pieri_factorizations(self, max_length=infinity):
            r"""
            Returns all factorizations of ``self`` as `uv`, where `u`
            is a Pieri factor and `v` is an element of the Weyl group.

            .. SEEALSO::

                * :meth:`WeylGroups.ParentMethods.pieri_factors`
                * :mod:`sage.combinat.root_system.pieri_factors`

            EXAMPLES:

            If we take `w = w_0` the maximal element of a strict parabolic
            subgroup of type `A_{n_1} \times \cdots \times A_{n_k}`, then the Pieri
            factorizations are in correspondence with all Pieri factors, and
            there are `\prod 2^{n_i}` of them::

                sage: W = WeylGroup(['A', 4, 1])
                sage: W.from_reduced_word([]).left_pieri_factorizations().cardinality()
                1
                sage: W.from_reduced_word([1]).left_pieri_factorizations().cardinality()
                2
                sage: W.from_reduced_word([1,2,1]).left_pieri_factorizations().cardinality()
                4
                sage: W.from_reduced_word([1,2,3,1,2,1]).left_pieri_factorizations().cardinality()
                8

                sage: W.from_reduced_word([1,3]).left_pieri_factorizations().cardinality()
                4
                sage: W.from_reduced_word([1,3,4,3]).left_pieri_factorizations().cardinality()
                8

                sage: W.from_reduced_word([2,1]).left_pieri_factorizations().cardinality()
                3
                sage: W.from_reduced_word([1,2]).left_pieri_factorizations().cardinality()
                2
                sage: [W.from_reduced_word([1,2]).left_pieri_factorizations(max_length=i).cardinality() for i in [-1, 0, 1, 2]]
                [0, 1, 2, 2]

                sage: W = WeylGroup(['C',4,1])
                sage: w = W.from_reduced_word([0,3,2,1,0])
                sage: w.left_pieri_factorizations().cardinality()
                7
                sage: [(u.reduced_word(),v.reduced_word()) for (u,v) in w.left_pieri_factorizations()]
                [([], [3, 2, 0, 1, 0]),
                ([0], [3, 2, 1, 0]),
                ([3], [2, 0, 1, 0]),
                ([3, 0], [2, 1, 0]),
                ([3, 2], [0, 1, 0]),
                ([3, 2, 0], [1, 0]),
                ([3, 2, 0, 1], [0])]

                sage: W = WeylGroup(['B',4,1])
                sage: W.from_reduced_word([0,2,1,0]).left_pieri_factorizations().cardinality()
                6
            """
            pieri_factors = self.parent().pieri_factors()

            def predicate(u):
                return u in pieri_factors and u.length() <= max_length

            return self.binary_factorizations(predicate)

        @cached_in_parent_method
        def stanley_symmetric_function_as_polynomial(self,
                                                     max_length=infinity):
            r"""
            Returns a multivariate generating function for the number
            of factorizations of a Weyl group element into Pieri
            factors of decreasing length, weighted by a statistic on
            Pieri factors.

            .. SEEALSO::

                * :meth:`stanley_symmetric_function`
                * :meth:`WeylGroups.ParentMethods.pieri_factors`
                * :mod:`sage.combinat.root_system.pieri_factors`

            INPUT:

                - ``self`` -- an element `w` of a Weyl group `W`
                - ``max_length`` -- a non negative integer or infinity (default: infinity)

            Returns the generating series for the Pieri factorizations
            `w = u_1 \cdots u_k`, where `u_i` is a Pieri factor for
            all `i`, `l(w) = \sum_{i=1}^k l(u_i)` and
            ``max_length`` `\geq l(u_1) \geq \cdots \geq l(u_k)`.

            A factorization `u_1 \cdots u_k` contributes a monomial of
            the form `\prod_i x_{l(u_i)}`, with coefficient given by
            `\prod_i 2^{c(u_i)}`, where `c` is a type-dependent
            statistic on Pieri factors, as returned by the method
            ``u[i].stanley_symm_poly_weight()``.

            EXAMPLES::

                sage: W = WeylGroup(['A', 3, 1])
                sage: W.from_reduced_word([]).stanley_symmetric_function_as_polynomial()
                1
                sage: W.from_reduced_word([1]).stanley_symmetric_function_as_polynomial()
                x1
                sage: W.from_reduced_word([1,2]).stanley_symmetric_function_as_polynomial()
                x1^2
                sage: W.from_reduced_word([2,1]).stanley_symmetric_function_as_polynomial()
                x1^2 + x2
                sage: W.from_reduced_word([1,2,1]).stanley_symmetric_function_as_polynomial()
                2*x1^3 + x1*x2
                sage: W.from_reduced_word([1,2,1,0]).stanley_symmetric_function_as_polynomial()
                3*x1^4 + 2*x1^2*x2 + x2^2 + x1*x3
                sage: W.from_reduced_word([1,2,3,1,2,1,0]).stanley_symmetric_function_as_polynomial() # long time
                22*x1^7 + 11*x1^5*x2 + 5*x1^3*x2^2 + 3*x1^4*x3 + 2*x1*x2^3 + x1^2*x2*x3
                sage: W.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function_as_polynomial() # long time
                8*x1^7 + 4*x1^5*x2 + 2*x1^3*x2^2 + x1*x2^3

                sage: W = WeylGroup(['C',3,1])
                sage: W.from_reduced_word([0,2,1,0]).stanley_symmetric_function_as_polynomial()
                32*x1^4 + 16*x1^2*x2 + 8*x2^2 + 4*x1*x3

                sage: W = WeylGroup(['B',3,1])
                sage: W.from_reduced_word([3,2,1]).stanley_symmetric_function_as_polynomial()
                2*x1^3 + x1*x2 + 1/2*x3

            Algorithm: Induction on the left Pieri factors. Note that
            this induction preserves subsets of `W` which are stable
            by taking right factors, and in particular Grassmanian
            elements.
            """
            W = self.parent()
            pieri_factors = W.pieri_factors()
            R = QQ[','.join('x%s' % l
                            for l in range(1,
                                           pieri_factors.max_length() + 1))]
            x = R.gens()
            if self.is_one():
                return R.one()

            return R(
                sum(2**(pieri_factors.stanley_symm_poly_weight(u)) *
                    x[u.length() - 1] *
                    v.stanley_symmetric_function_as_polynomial(
                        max_length=u.length())
                    for (u, v) in self.left_pieri_factorizations(max_length)
                    if u != W.one()))

        def stanley_symmetric_function(self):
            r"""
            Return the affine Stanley symmetric function indexed by ``self``.

            INPUT:

            - ``self`` -- an element `w` of a Weyl group

            Returns the affine Stanley symmetric function indexed by
            `w`. Stanley symmetric functions are defined as generating
            series of the factorizations of `w` into Pieri factors and
            weighted by a statistic on Pieri factors.

            .. SEEALSO::

                * :meth:`stanley_symmetric_function_as_polynomial`
                * :meth:`WeylGroups.ParentMethods.pieri_factors`
                * :mod:`sage.combinat.root_system.pieri_factors`

            EXAMPLES::

                sage: W = WeylGroup(['A', 3, 1])
                sage: W.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function()
                8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1]
                sage: A = AffinePermutationGroup(['A',3,1])
                sage: A.from_reduced_word([3,1,2,0,3,1,0]).stanley_symmetric_function()
                8*m[1, 1, 1, 1, 1, 1, 1] + 4*m[2, 1, 1, 1, 1, 1] + 2*m[2, 2, 1, 1, 1] + m[2, 2, 2, 1]

                sage: W = WeylGroup(['C',3,1])
                sage: W.from_reduced_word([0,2,1,0]).stanley_symmetric_function()
                32*m[1, 1, 1, 1] + 16*m[2, 1, 1] + 8*m[2, 2] + 4*m[3, 1]

                sage: W = WeylGroup(['B',3,1])
                sage: W.from_reduced_word([3,2,1]).stanley_symmetric_function()
                2*m[1, 1, 1] + m[2, 1] + 1/2*m[3]

                sage: W = WeylGroup(['B',4])
                sage: w = W.from_reduced_word([3,2,3,1])
                sage: w.stanley_symmetric_function()  # long time (6s on sage.math, 2011)
                48*m[1, 1, 1, 1] + 24*m[2, 1, 1] + 12*m[2, 2] + 8*m[3, 1] + 2*m[4]

                sage: A = AffinePermutationGroup(['A',4,1])
                sage: a = A([-2,0,1,4,12])
                sage: a.stanley_symmetric_function()
                6*m[1, 1, 1, 1, 1, 1, 1, 1] + 5*m[2, 1, 1, 1, 1, 1, 1] + 4*m[2, 2, 1, 1, 1, 1]
                + 3*m[2, 2, 2, 1, 1] + 2*m[2, 2, 2, 2] + 4*m[3, 1, 1, 1, 1, 1] + 3*m[3, 2, 1, 1, 1]
                + 2*m[3, 2, 2, 1] + 2*m[3, 3, 1, 1] + m[3, 3, 2] + 3*m[4, 1, 1, 1, 1] + 2*m[4, 2, 1, 1]
                + m[4, 2, 2] + m[4, 3, 1]

            One more example (:trac:`14095`)::

                sage: G = SymmetricGroup(4)
                sage: w = G.from_reduced_word([3,2,3,1])
                sage: w.stanley_symmetric_function()
                3*m[1, 1, 1, 1] + 2*m[2, 1, 1] + m[2, 2] + m[3, 1]

            REFERENCES:

            .. [BH1994] S. Billey, M. Haiman. *Schubert polynomials for the
               classical groups*. J. Amer. Math. Soc., 1994.
            .. [Lam2008] T. Lam. *Schubert polynomials for the affine
               Grassmannian*. J. Amer. Math. Soc., 2008.
            .. [LSS2009] T. Lam, A. Schilling, M. Shimozono. *Schubert
               polynomials for the affine Grassmannian of the symplectic
               group*. Mathematische Zeitschrift 264(4) (2010) 765-811
               (:arxiv:`0710.2720`)
            .. [Pon2010] S. Pon. *Types B and D affine Stanley symmetric
               functions*, unpublished PhD Thesis, UC Davis, 2010.
            """
            import sage.combinat.sf
            m = sage.combinat.sf.sf.SymmetricFunctions(QQ).monomial()
            return m.from_polynomial_exp(
                self.stanley_symmetric_function_as_polynomial())

        @cached_in_parent_method
        def reflection_to_root(self):
            r"""
            Returns the root associated with the reflection ``self``.

            EXAMPLES::

                sage: W=WeylGroup(['C',2],prefix="s")
                sage: r=W.from_reduced_word([1,2,1])
                sage: r.reflection_to_root()
                2*alpha[1] + alpha[2]
                sage: r=W.from_reduced_word([1,2])
                sage: r.reflection_to_root()
                Traceback (most recent call last):
                ...
                ValueError: s1*s2 is not a reflection
                sage: W.long_element().reflection_to_root()
                Traceback (most recent call last):
                ...
                ValueError: s2*s1*s2*s1 is not a reflection

            """

            i = self.first_descent()
            if i is None:
                raise ValueError("{} is not a reflection".format(self))
            if self == self.parent().simple_reflection(i):
                return self.parent().cartan_type().root_system().root_lattice(
                ).simple_root(i)
            w = self.apply_simple_reflection(i, side='right')
            if not w.has_descent(i, side='left'):
                raise ValueError("{} is not a reflection".format(self))
            return ((w.apply_simple_reflection(
                i, side='left')).reflection_to_root()).simple_reflection(i)

        @cached_in_parent_method
        def reflection_to_coroot(self):
            r"""
            Returns the coroot associated with the reflection ``self``.

            EXAMPLES::

                sage: W=WeylGroup(['C',2],prefix="s")
                sage: r=W.from_reduced_word([1,2,1])
                sage: r.reflection_to_coroot()
                alphacheck[1] + alphacheck[2]
                sage: r=W.from_reduced_word([1,2])
                sage: r.reflection_to_coroot()
                Traceback (most recent call last):
                ...
                ValueError: s1*s2 is not a reflection
                sage: W.long_element().reflection_to_coroot()
                Traceback (most recent call last):
                ...
                ValueError: s2*s1*s2*s1 is not a reflection

            """

            i = self.first_descent()
            if i is None:
                raise ValueError("{} is not a reflection".format(self))
            if self == self.parent().simple_reflection(i):
                return self.parent().cartan_type().root_system().root_lattice(
                ).simple_coroot(i)
            w = self.apply_simple_reflection(i, side='right')
            if not w.has_descent(i, side='left'):
                raise ValueError("{} is not a reflection".format(self))
            return ((w.apply_simple_reflection(
                i, side='left')).reflection_to_coroot()).simple_reflection(i)

        def inversions(self, side='right', inversion_type='reflections'):
            """
            Returns the set of inversions of ``self``.

            INPUT:

            - ``side`` -- 'right' (default) or 'left'
            - ``inversion_type`` -- 'reflections' (default), 'roots', or 'coroots'.

            OUTPUT:

            For reflections, the set of reflections r in the Weyl group such that
            ``self`` ``r`` < ``self``. For (co)roots, the set of positive (co)roots that are sent
            by ``self`` to negative (co)roots; their associated reflections are described above.

            If ``side`` is 'left', the inverse Weyl group element is used.

            EXAMPLES::

                sage: W=WeylGroup(['C',2], prefix="s")
                sage: w=W.from_reduced_word([1,2])
                sage: w.inversions()
                [s2, s2*s1*s2]
                sage: w.inversions(inversion_type = 'reflections')
                [s2, s2*s1*s2]
                sage: w.inversions(inversion_type = 'roots')
                [alpha[2], alpha[1] + alpha[2]]
                sage: w.inversions(inversion_type = 'coroots')
                [alphacheck[2], alphacheck[1] + 2*alphacheck[2]]
                sage: w.inversions(side = 'left')
                [s1, s1*s2*s1]
                sage: w.inversions(side = 'left', inversion_type = 'roots')
                [alpha[1], 2*alpha[1] + alpha[2]]
                sage: w.inversions(side = 'left', inversion_type = 'coroots')
                [alphacheck[1], alphacheck[1] + alphacheck[2]]

            """

            if side == 'left':
                self = self.inverse()
            reflections = self.inversions_as_reflections()
            if inversion_type == 'reflections':
                return reflections
            if inversion_type == 'roots':
                return [r.reflection_to_root() for r in reflections]
            if inversion_type == 'coroots':
                return [r.reflection_to_coroot() for r in reflections]
            raise ValueError(
                "inversion_type {} is invalid".format(inversion_type))

        def inversion_arrangement(self, side='right'):
            r"""
            Return the inversion hyperplane arrangement of ``self``.

            INPUT:

            - ``side`` -- ``'right'`` (default) or ``'left'``

            OUTPUT:

            A (central) hyperplane arrangement whose hyperplanes correspond
            to the inversions of ``self`` given as roots.

            The ``side`` parameter determines on which side
            to compute the inversions.

            EXAMPLES::

                sage: W = WeylGroup(['A',3])
                sage: w = W.from_reduced_word([1, 2, 3, 1, 2])
                sage: A = w.inversion_arrangement(); A
                Arrangement of 5 hyperplanes of dimension 3 and rank 3
                sage: A.hyperplanes()
                (Hyperplane 0*a1 + 0*a2 + a3 + 0,
                 Hyperplane 0*a1 + a2 + 0*a3 + 0,
                 Hyperplane 0*a1 + a2 + a3 + 0,
                 Hyperplane a1 + a2 + 0*a3 + 0,
                 Hyperplane a1 + a2 + a3 + 0)

            The identity element gives the empty arrangement::

                sage: W = WeylGroup(['A',3])
                sage: W.one().inversion_arrangement()
                Empty hyperplane arrangement of dimension 3
            """
            inv = self.inversions(side=side, inversion_type='roots')
            from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements
            I = self.parent().cartan_type().index_set()
            H = HyperplaneArrangements(QQ, tuple(['a{}'.format(i) for i in I]))
            gens = H.gens()
            if not inv:
                return H()
            return H(
                [sum(c * gens[I.index(i)] for (i, c) in root) for root in inv])

        def bruhat_lower_covers_coroots(self):
            r"""
            Returns all 2-tuples (``v``, `\alpha`) where ``v`` is covered by ``self`` and `\alpha`
            is the positive coroot such that ``self`` = ``v`` `s_\alpha` where `s_\alpha` is
            the reflection orthogonal to `\alpha`.

            ALGORITHM:

            See :meth:`.bruhat_lower_covers` and :meth:`.bruhat_lower_covers_reflections` for Coxeter groups.

            EXAMPLES::

                sage: W = WeylGroup(['A',3], prefix="s")
                sage: w = W.from_reduced_word([3,1,2,1])
                sage: w.bruhat_lower_covers_coroots()
                [(s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3]), (s3*s2*s1, alphacheck[2]), (s3*s1*s2, alphacheck[1])]

            """

            return [(x[0], x[1].reflection_to_coroot())
                    for x in self.bruhat_lower_covers_reflections()]

        def bruhat_upper_covers_coroots(self):
            r"""
            Returns all 2-tuples (``v``, `\alpha`) where ``v`` is covers ``self`` and `\alpha`
            is the positive coroot such that ``self`` = ``v`` `s_\alpha` where `s_\alpha` is
            the reflection orthogonal to `\alpha`.

            ALGORITHM:

            See :meth:`~CoxeterGroups.ElementMethods.bruhat_upper_covers` and :meth:`.bruhat_upper_covers_reflections` for Coxeter groups.

            EXAMPLES::

                sage: W = WeylGroup(['A',4], prefix="s")
                sage: w = W.from_reduced_word([3,1,2,1])
                sage: w.bruhat_upper_covers_coroots()
                [(s1*s2*s3*s2*s1, alphacheck[3]), (s2*s3*s1*s2*s1, alphacheck[2] + alphacheck[3]), (s3*s4*s1*s2*s1, alphacheck[4]), (s4*s3*s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3] + alphacheck[4])]

            """

            return [(x[0], x[1].reflection_to_coroot())
                    for x in self.bruhat_upper_covers_reflections()]

        def quantum_bruhat_successors(self,
                                      index_set=None,
                                      roots=False,
                                      quantum_only=False):
            r"""
            Returns the successors of ``self`` in the parabolic quantum Bruhat graph.

            INPUT:

            - ``self`` -- a Weyl group element, which is assumed to be of minimum length in its coset with respect to the parabolic subgroup

            - ``index_set`` -- (default: None) indicates the set of simple reflections used to generate the parabolic subgroup;
               the default value indicates that the subgroup is the identity

            - ``roots`` -- (default: False) if True, returns the list of 2-tuples (``w``, `\alpha`) where ``w`` is a
               successor and `\alpha` is the positive root associated with the successor relation.

            - ``quantum_only`` -- (default: False) if True, returns only the quantum successors

            Returns the successors of ``self`` in the quantum Bruhat graph on the parabolic
            quotient of the Weyl group determined by the subset of Dynkin nodes ``index_set``.

            EXAMPLES::

                sage: W = WeylGroup(['A',3], prefix="s")
                sage: w = W.from_reduced_word([3,1,2])
                sage: w.quantum_bruhat_successors([1], roots = True)
                [(s3, alpha[2]), (s1*s2*s3*s2, alpha[3]), (s2*s3*s1*s2, alpha[1] + alpha[2] + alpha[3])]
                sage: w.quantum_bruhat_successors([1,3])
                [1, s2*s3*s1*s2]
                sage: w.quantum_bruhat_successors(roots = True)
                [(s3*s1*s2*s1, alpha[1]), (s3*s1, alpha[2]), (s1*s2*s3*s2, alpha[3]), (s2*s3*s1*s2, alpha[1] + alpha[2] + alpha[3])]
                sage: w.quantum_bruhat_successors()
                [s3*s1*s2*s1, s3*s1, s1*s2*s3*s2, s2*s3*s1*s2]
                sage: w.quantum_bruhat_successors(quantum_only = True)
                [s3*s1]
                sage: w = W.from_reduced_word([2,3])
                sage: w.quantum_bruhat_successors([1,3])
                Traceback (most recent call last):
                ...
                ValueError: s2*s3 is not of minimum length in its coset of the parabolic subgroup generated by the reflections (1, 3)

            """
            W = self.parent()
            if not W.cartan_type().is_finite():
                raise ValueError("The Cartan type {} is not finite".format(
                    W.cartan_type()))
            if index_set is None:
                index_set = []
            else:
                index_set = [x for x in index_set]
            index_set = tuple(index_set)
            if self != self.coset_representative(index_set):
                raise ValueError(
                    "{} is not of minimum length in its coset of the parabolic subgroup generated by the reflections {}"
                    .format(self, index_set))
            lattice = W.cartan_type().root_system().root_lattice()
            w_length_plus_one = self.length() + 1
            successors = []
            for alpha in lattice.nonparabolic_positive_roots(index_set):
                wr = self * W.from_reduced_word(alpha.associated_reflection())
                wrc = wr.coset_representative(index_set)
                if wrc == wr and wr.length(
                ) == w_length_plus_one and not quantum_only:
                    if roots:
                        successors.append((wr, alpha))
                    else:
                        successors.append(wr)
                elif alpha.quantum_root() and wrc.length(
                ) == w_length_plus_one - lattice.nonparabolic_positive_root_sum(
                        index_set).scalar(alpha.associated_coroot()):
                    if roots:
                        successors.append((wrc, alpha))
                    else:
                        successors.append(wrc)
            return successors
Ejemplo n.º 3
0
class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring):
    """
    The category of Hopf algebras with a distinguished basis

    EXAMPLES::

        sage: C = HopfAlgebrasWithBasis(QQ)
        sage: C
        Category of hopf algebras with basis over Rational Field
        sage: C.super_categories()
        [Category of hopf algebras over Rational Field,
         Category of bialgebras with basis over Rational Field]

    We now show how to use a simple Hopf algebra, namely the group algebra of the dihedral group
    (see also AlgebrasWithBasis)::

        sage: A = C.example(); A
        An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
        sage: A.__custom_name = "A"
        sage: A.category()
        Category of finite dimensional hopf algebras with basis over Rational Field

        sage: A.one_basis()
        ()
        sage: A.one()
        B[()]

        sage: A.base_ring()
        Rational Field
        sage: A.basis().keys()
        Dihedral group of order 6 as a permutation group

        sage: [a,b] = A.algebra_generators()
        sage: a, b
        (B[(1,2,3)], B[(1,3)])
        sage: a^3, b^2
        (B[()], B[()])
        sage: a*b
        B[(1,2)]

        sage: A.product           # todo: not quite ...
        <bound method MyGroupAlgebra_with_category._product_from_product_on_basis_multiply of A>
        sage: A.product(b,b)
        B[()]

        sage: A.zero().coproduct()
        0
        sage: A.zero().coproduct().parent()
        A # A
        sage: a.coproduct()
        B[(1,2,3)] # B[(1,2,3)]

        sage: TestSuite(A).run(verbose=True)
        running ._test_additive_associativity() . . . pass
        running ._test_an_element() . . . pass
        running ._test_antipode() . . . pass
        running ._test_associativity() . . . pass
        running ._test_cardinality() . . . pass
        running ._test_category() . . . pass
        running ._test_characteristic() . . . pass
        running ._test_distributivity() . . . pass
        running ._test_elements() . . .
          Running the test suite of self.an_element()
          running ._test_category() . . . pass
          running ._test_eq() . . . pass
          running ._test_new() . . . pass
          running ._test_nonzero_equal() . . . pass
          running ._test_not_implemented_methods() . . . pass
          running ._test_pickling() . . . pass
          pass
        running ._test_elements_eq_reflexive() . . . pass
        running ._test_elements_eq_symmetric() . . . pass
        running ._test_elements_eq_transitive() . . . pass
        running ._test_elements_neq() . . . pass
        running ._test_eq() . . . pass
        running ._test_new() . . . pass
        running ._test_not_implemented_methods() . . . pass
        running ._test_one() . . . pass
        running ._test_pickling() . . . pass
        running ._test_prod() . . . pass
        running ._test_some_elements() . . . pass
        running ._test_zero() . . . pass
        sage: A.__class__
        <class 'sage.categories.examples.hopf_algebras_with_basis.MyGroupAlgebra_with_category'>
        sage: A.element_class
        <class 'sage.categories.examples.hopf_algebras_with_basis.MyGroupAlgebra_with_category.element_class'>

    Let us look at the code for implementing A::

        sage: A??                       # todo: not implemented

    TESTS::

        sage: TestSuite(A).run()
        sage: TestSuite(C).run()
    """
    def example(self, G=None):
        """
        Returns an example of algebra with basis::

            sage: HopfAlgebrasWithBasis(QQ['x']).example()
            An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Univariate Polynomial Ring in x over Rational Field

        An other group can be specified as optional argument::

            sage: HopfAlgebrasWithBasis(QQ).example(SymmetricGroup(4))
            An example of Hopf algebra with basis: the group algebra of the Symmetric group of order 4! as a permutation group over Rational Field
        """
        from sage.categories.examples.hopf_algebras_with_basis import MyGroupAlgebra
        from sage.groups.perm_gps.permgroup_named import DihedralGroup
        if G is None:
            G = DihedralGroup(3)
        return MyGroupAlgebra(self.base_ring(), G)

#     This is only correct in the finite dimensional / graded case
#     def dual(self):
#         """
#         Returns the dual category

#         EXAMPLES:

#         The category of Hopf algebras over any field is self dual::

#             sage: C = HopfAlgebrasWithBasis(QQ)
#             sage: C.dual()
#             Category of hopf algebras with basis over Rational Field
#         """
#         return self

    FiniteDimensional = LazyImport(
        'sage.categories.finite_dimensional_hopf_algebras_with_basis',
        'FiniteDimensionalHopfAlgebrasWithBasis')
    Filtered = LazyImport('sage.categories.filtered_hopf_algebras_with_basis',
                          'FilteredHopfAlgebrasWithBasis')
    Graded = LazyImport('sage.categories.graded_hopf_algebras_with_basis',
                        'GradedHopfAlgebrasWithBasis')
    Super = LazyImport('sage.categories.super_hopf_algebras_with_basis',
                       'SuperHopfAlgebrasWithBasis')

    class ParentMethods:
        @abstract_method(optional=True)
        def antipode_on_basis(self, x):
            """
            The antipode of the Hopf algebra on the basis (optional)

            INPUT:

             - ``x`` -- an index of an element of the basis of ``self``

            Returns the antipode of the basis element indexed by ``x``.

            If this method is implemented, then :meth:`antipode` is defined
            from this by linearity.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example()
                sage: W = A.basis().keys(); W
                Dihedral group of order 6 as a permutation group
                sage: w = W.gen(0); w
                (1,2,3)
                sage: A.antipode_on_basis(w)
                B[(1,3,2)]
            """

        @lazy_attribute
        def antipode(self):
            """
            The antipode of this Hopf algebra.

            If :meth:`.antipode_basis` is available, this constructs the
            antipode morphism from ``self`` to ``self`` by extending it by
            linearity. Otherwise, :meth:`self.antipode_by_coercion` is used, if
            available.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(ZZ).example(); A
                An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Integer Ring
                sage: A = HopfAlgebrasWithBasis(QQ).example()
                sage: [a,b] = A.algebra_generators()
                sage: a, A.antipode(a)
                (B[(1,2,3)], B[(1,3,2)])
                sage: b, A.antipode(b)
                (B[(1,3)], B[(1,3)])

            TESTS::

                sage: all(A.antipode(x) * x == A.one() for x in A.basis())
                True
            """
            if self.antipode_on_basis is not NotImplemented:
                # Should give the information that this is an anti-morphism of algebra
                return self._module_morphism(self.antipode_on_basis,
                                             codomain=self)
            elif hasattr(self, "antipode_by_coercion"):
                return self.antipode_by_coercion

        def _test_antipode(self, **options):
            r"""
            Test the antipode.

            An *antipode* `S` of a Hopf algebra is a linear endomorphism of the
            Hopf algebra that satisfies the following conditions (see
            :wikipedia:`HopfAlgebra`).

            - If `\mu` and `\Delta` denote the product and coproduct of the
              Hopf algebra, respectively, then `S` satisfies

              .. MATH::

                  \mu \circ (S \tensor 1) \circ \Delta = unit \circ counit
                  \mu \circ (1 \tensor S) \circ \Delta = unit \circ counit

            - `S` is an *anti*-homomorphism

            These properties are tested on :meth:`some_elements`.

            TESTS::

                sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon()
                sage: R._test_antipode()

            ::

                sage: s = SymmetricFunctions(QQ).schur()
                sage: s._test_antipode()

            """
            tester = self._tester(**options)

            S = self.antipode

            IS = lambda x: self.sum(c * self.monomial(t1) * S(self.monomial(
                t2)) for ((t1, t2), c) in x.coproduct())

            SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(
                t2) for ((t1, t2), c) in x.coproduct())

            for x in tester.some_elements():

                # antipode is an anti-homomorphism
                for y in tester.some_elements():
                    tester.assertTrue(S(x) * S(y) == S(y * x))

                # mu * (S # I) * delta == counit * unit
                tester.assertTrue(SI(x) == self.counit(x) * self.one())

                # mu * (I # S) * delta == counit * unit
                tester.assertTrue(IS(x) == self.counit(x) * self.one())

    class ElementMethods:
        pass

    class TensorProducts(TensorProductsCategory):
        """
        The category of hopf algebras with basis constructed by tensor product of hopf algebras with basis
        """
        @cached_method
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: C = HopfAlgebrasWithBasis(QQ).TensorProducts()
                sage: C.extra_super_categories()
                [Category of hopf algebras with basis over Rational Field]
                sage: sorted(C.super_categories(), key=str)
                [Category of hopf algebras with basis over Rational Field,
                 Category of tensor products of algebras with basis over Rational Field,
                 Category of tensor products of hopf algebras over Rational Field]
            """
            return [self.base_category()]

        class ParentMethods:
            # todo: antipode
            pass

        class ElementMethods:
            pass
Ejemplo n.º 4
0
    class ParentMethods:
        @abstract_method
        def le(self, x, y):
            r"""
            Return whether `x \le y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.le( 3, 6 )
                True
                sage: D.le( 3, 3 )
                True
                sage: D.le( 3, 5 )
                False
            """

        def lt(self, x, y):
            r"""
            Return whether `x < y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`le`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.lt( 3, 6 )
                True
                sage: D.lt( 3, 3 )
                False
                sage: D.lt( 3, 5 )
                False
            """
            return self.le(x, y) and x != y

        def ge(self, x, y):
            r"""
            Return whether `x \ge y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`le`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.ge( 6, 3 )
                True
                sage: D.ge( 3, 3 )
                True
                sage: D.ge( 3, 5 )
                False
            """
            return self.le(y, x)

        def gt(self, x, y):
            r"""
            Return whether `x > y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`lt`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.gt( 3, 6 )
                False
                sage: D.gt( 3, 3 )
                False
                sage: D.gt( 3, 5 )
                False
            """
            return self.lt(y, x)

        @abstract_method(optional=True)
        def upper_covers(self, x):
            r"""
            Return the upper covers of `x`, that is, the elements `y`
            such that `x<y` and there exists no `z` such that `x<z<y`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.upper_covers(3)
                [6, 15]
            """

        @abstract_method(optional=True)
        def lower_covers(self, x):
            r"""
            Return the lower covers of `x`, that is, the elements `y`
            such that `y<x` and there exists no `z` such that `y<z<x`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.lower_covers(15)
                [3, 5]
            """

        @abstract_method(optional=True)
        def order_ideal(self, elements):
            r"""
            Return the order ideal in ``self`` generated by the elements
            of an iterable ``elements``.

            A subset `I` of a poset is said to be an order ideal if, for
            any `x` in `I` and `y` such that `y \le x`, then `y` is in `I`.

            This is also called the lower set generated by these elements.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.order_ideal([7,10])
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]
            """

        @abstract_method(optional=True)
        def order_filter(self, elements):
            r"""
            Return the order filter generated by a list of elements.

            A subset `I` of a poset is said to be an order filter if, for
            any `x` in `I` and `y` such that `y \ge x`, then `y` is in `I`.

            This is also called the upper set generated by these elements.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.order_filter([3,8])
                [3, 7, 8, 9, 10, 11, 12, 13, 14, 15]
            """

        def directed_subset(self, elements, direction):
            r"""
            Return the order filter or the order ideal generated by a
            list of elements.

            If ``direction`` is 'up', the order filter (upper set) is
            being returned.

            If ``direction`` is 'down', the order ideal (lower set) is
            being returned.

            INPUT:

            - elements -- a list of elements.

            - direction -- 'up' or 'down'.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.directed_subset([3, 8], 'up')
                [3, 7, 8, 9, 10, 11, 12, 13, 14, 15]
                sage: B.directed_subset([7, 10], 'down')
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]
            """
            if direction == 'up':
                return self.order_filter(elements)
            if direction == 'down':
                return self.order_ideal(elements)
            raise ValueError("Direction must be either 'up' or 'down'.")

        def principal_order_ideal(self, x):
            r"""
            Return the order ideal generated by an element ``x``.

            This is also called the lower set generated by this element.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.principal_order_ideal(6)
                [0, 2, 4, 6]
            """
            return self.order_ideal([x])

        principal_lower_set = principal_order_ideal

        def principal_order_filter(self, x):
            r"""
            Return the order filter generated by an element ``x``.

            This is also called the upper set generated by this element.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.principal_order_filter(2)
                [2, 3, 6, 7, 10, 11, 14, 15]
            """
            return self.order_filter([x])

        principal_upper_set = principal_order_filter

        def order_ideal_toggle(self, I, v):
            r"""
            Return the result of toggling the element ``v`` in the
            order ideal ``I``.

            If `v` is an element of a poset `P`, then toggling the
            element `v` is an automorphism of the set `J(P)` of all
            order ideals of `P`. It is defined as follows: If `I`
            is an order ideal of `P`, then the image of `I` under
            toggling the element `v` is

            - the set `I \cup \{ v \}`, if `v \not\in I` but
              every element of `P` smaller than `v` is in `I`;

            - the set `I \setminus \{ v \}`, if `v \in I` but
              no element of `P` greater than `v` is in `I`;

            - `I` otherwise.

            This image always is an order ideal of `P`.

            EXAMPLES::

                sage: P = Poset({1: [2,3], 2: [4], 3: []})
                sage: I = Set({1, 2})
                sage: I in P.order_ideals_lattice()
                True
                sage: P.order_ideal_toggle(I, 1)
                {1, 2}
                sage: P.order_ideal_toggle(I, 2)
                {1}
                sage: P.order_ideal_toggle(I, 3)
                {1, 2, 3}
                sage: P.order_ideal_toggle(I, 4)
                {1, 2, 4}
                sage: P4 = Posets(4)
                sage: all(all(all(P.order_ideal_toggle(P.order_ideal_toggle(I, i), i) == I
                ....:               for i in range(4))
                ....:          for I in P.order_ideals_lattice(facade=True))
                ....:     for P in P4)
                True
            """
            if not v in I:
                if all(u in I for u in self.lower_covers(v)):
                    from sage.sets.set import Set
                    return I.union(Set({v}))
            else:
                if all(u not in I for u in self.upper_covers(v)):
                    from sage.sets.set import Set
                    return I.difference(Set({v}))
            return I

        def order_ideal_toggles(self, I, vs):
            r"""
            Return the result of toggling the elements of the list (or
            iterable) ``vs`` (one by one, from left to right) in the order
            ideal ``I``.

            See :meth:`order_ideal_toggle` for a definition of toggling.

            EXAMPLES::

                sage: P = Poset({1: [2,3], 2: [4], 3: []})
                sage: I = Set({1, 2})
                sage: P.order_ideal_toggles(I, [1,2,3,4])
                {1, 3}
                sage: P.order_ideal_toggles(I, (1,2,3,4))
                {1, 3}
            """
            for v in vs:
                I = self.order_ideal_toggle(I, v)
            return I

        def is_order_ideal(self, o):
            """
            Return whether ``o`` is an order ideal of ``self``, assuming ``self``
            has no infinite descending path.

            INPUT:

            - ``o`` -- a list (or set, or tuple) containing some elements of ``self``

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_order_ideal([1, 3])
                True
                sage: P.is_order_ideal([])
                True
                sage: P.is_order_ideal({1, 3})
                True
                sage: P.is_order_ideal([1, 3, 4])
                False

            """
            return all((u in self and all(x in o
                                          for x in self.lower_covers(u)))
                       for u in o)

        def is_order_filter(self, o):
            """
            Return whether ``o`` is an order filter of ``self``, assuming ``self``
            has no infinite ascending path.

            INPUT:

            - ``o`` -- a list (or set, or tuple) containing some elements of ``self``

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_order_filter([4, 12])
                True
                sage: P.is_order_filter([])
                True
                sage: P.is_order_filter({3, 4, 12})
                False
                sage: P.is_order_filter({3, 6, 12})
                True

            """
            return all((u in self and all(x in o
                                          for x in self.upper_covers(u)))
                       for u in o)

        def is_chain_of_poset(self, o, ordered=False):
            """
            Return whether an iterable ``o`` is a chain of ``self``,
            including a check for ``o`` being ordered from smallest
            to largest element if the keyword ``ordered`` is set to
            ``True``.

            INPUT:

            - ``o`` -- an iterable (e. g., list, set, or tuple)
              containing some elements of ``self``

            - ``ordered`` -- a Boolean (default: ``False``) which
              decides whether the notion of a chain includes being
              ordered

            OUTPUT:

            If ``ordered`` is set to ``False``, the truth value of
            the following assertion is returned: The subset of ``self``
            formed by the elements of ``o`` is a chain in ``self``.

            If ``ordered`` is set to ``True``, the truth value of
            the following assertion is returned: Every element of the
            list ``o`` is (strictly!) smaller than its successor in
            ``self``. (This makes no sense if ``ordered`` is a set.)

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_chain_of_poset([1, 3])
                True
                sage: P.is_chain_of_poset([3, 1])
                True
                sage: P.is_chain_of_poset([1, 3], ordered=True)
                True
                sage: P.is_chain_of_poset([3, 1], ordered=True)
                False
                sage: P.is_chain_of_poset([])
                True
                sage: P.is_chain_of_poset([], ordered=True)
                True
                sage: P.is_chain_of_poset((2, 12, 6))
                True
                sage: P.is_chain_of_poset((2, 6, 12), ordered=True)
                True
                sage: P.is_chain_of_poset((2, 12, 6), ordered=True)
                False
                sage: P.is_chain_of_poset((2, 12, 6, 3))
                False
                sage: P.is_chain_of_poset((2, 3))
                False

                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
                sage: Q.is_chain_of_poset([1, 2], ordered=True)
                False
                sage: Q.is_chain_of_poset([1, 2])
                True
                sage: Q.is_chain_of_poset([2, 1], ordered=True)
                True
                sage: Q.is_chain_of_poset([2, 1, 1], ordered=True)
                False
                sage: Q.is_chain_of_poset([3])
                True
                sage: Q.is_chain_of_poset([4, 2, 3])
                True
                sage: Q.is_chain_of_poset([4, 2, 3], ordered=True)
                False
                sage: Q.is_chain_of_poset([2, 3, 4], ordered=True)
                True

            Examples with infinite posets::

                sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion
                sage: R = FiniteSetsOrderedByInclusion()
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))])
                False
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))], ordered=True)
                False
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))])
                True

                sage: from sage.categories.examples.posets import PositiveIntegersOrderedByDivisibilityFacade
                sage: T = PositiveIntegersOrderedByDivisibilityFacade()
                sage: T.is_chain_of_poset((T(3), T(4), T(7)))
                False
                sage: T.is_chain_of_poset((T(3), T(6), T(3)))
                True
                sage: T.is_chain_of_poset((T(3), T(6), T(3)), ordered=True)
                False
                sage: T.is_chain_of_poset((T(3), T(3), T(6)))
                True
                sage: T.is_chain_of_poset((T(3), T(3), T(6)), ordered=True)
                False
                sage: T.is_chain_of_poset((T(3), T(6)), ordered=True)
                True
                sage: T.is_chain_of_poset((), ordered=True)
                True
                sage: T.is_chain_of_poset((T(3),), ordered=True)
                True
                sage: T.is_chain_of_poset((T(q) for q in divisors(27)))
                True
                sage: T.is_chain_of_poset((T(q) for q in divisors(18)))
                False
            """
            list_o = list(o)
            if ordered:
                return all(self.lt(a, b) for a, b in zip(list_o, list_o[1:]))
            else:
                for (i, x) in enumerate(list_o):
                    for y in list_o[:i]:
                        if (not self.le(x, y)) and (not self.gt(x, y)):
                            return False
                return True

        def is_antichain_of_poset(self, o):
            """
            Return whether an iterable ``o`` is an antichain of
            ``self``.

            INPUT:

            - ``o`` -- an iterable (e. g., list, set, or tuple)
              containing some elements of ``self``

            OUTPUT:

            ``True`` if the subset of ``self`` consisting of the entries
            of ``o`` is an antichain of ``self``, and ``False`` otherwise.

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_antichain_of_poset([1, 3])
                False
                sage: P.is_antichain_of_poset([3, 1])
                False
                sage: P.is_antichain_of_poset([1, 1, 3])
                False
                sage: P.is_antichain_of_poset([])
                True
                sage: P.is_antichain_of_poset([1])
                True
                sage: P.is_antichain_of_poset([1, 1])
                True
                sage: P.is_antichain_of_poset([3, 4])
                True
                sage: P.is_antichain_of_poset([3, 4, 12])
                False
                sage: P.is_antichain_of_poset([6, 4])
                True
                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 < i and i < 6))
                True
                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 <= i and i < 6))
                False

                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
                sage: Q.is_antichain_of_poset((1, 2))
                False
                sage: Q.is_antichain_of_poset((2, 4))
                False
                sage: Q.is_antichain_of_poset((4, 2))
                False
                sage: Q.is_antichain_of_poset((2, 2))
                True
                sage: Q.is_antichain_of_poset((3, 4))
                False
                sage: Q.is_antichain_of_poset((3, 1))
                True
                sage: Q.is_antichain_of_poset((1, ))
                True
                sage: Q.is_antichain_of_poset(())
                True

            An infinite poset::

                sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion
                sage: R = FiniteSetsOrderedByInclusion()
                sage: R.is_antichain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))])
                True
                sage: R.is_antichain_of_poset([R(set([3, 1, 2, 4])), R(set([1, 4])), R(set([4, 5]))])
                False
            """
            return all(not self.lt(x, y) for x in o for y in o)

        CartesianProduct = LazyImport('sage.combinat.posets.cartesian_product',
                                      'CartesianProductPoset')
Ejemplo n.º 5
0
class Modules(Category_module):
    r"""
    The category of all modules over a base ring `R`.

    An `R`-module `M` is a left and right `R`-module over a
    commutative ring `R` such that:

    .. MATH::

        r*(x*s) = (r*x)*s \qquad  \forall r,s \in R \text{ and } x \in M

    INPUT:

    - ``base_ring`` -- a ring `R` or subcategory of ``Rings()``
    - ``dispatch`` -- a boolean (for internal use; default: ``True``)

    When the base ring is a field, the category of vector spaces is
    returned instead (unless ``dispatch == False``).

    .. WARNING::

        Outside of the context of symmetric modules over a commutative
        ring, the specifications of this category are fuzzy and not
        yet set in stone (see below). The code in this category and
        its subcategories is therefore prone to bugs or arbitrary
        limitations in this case.

    EXAMPLES::

        sage: Modules(ZZ)
        Category of modules over Integer Ring
        sage: Modules(QQ)
        Category of vector spaces over Rational Field

        sage: Modules(Rings())
        Category of modules over rings
        sage: Modules(FiniteFields())
        Category of vector spaces over finite enumerated fields

        sage: Modules(Integers(9))
        Category of modules over Ring of integers modulo 9

        sage: Modules(Integers(9)).super_categories()
        [Category of bimodules over Ring of integers modulo 9 on the left and Ring of integers modulo 9 on the right]

        sage: Modules(ZZ).super_categories()
        [Category of bimodules over Integer Ring on the left and Integer Ring on the right]

        sage: Modules == RingModules
        True

        sage: Modules(ZZ['x']).is_abelian()   # see #6081
        True

    TESTS::

        sage: TestSuite(Modules(ZZ)).run()

    .. TODO::

        - Clarify the distinction, if any, with ``BiModules(R, R)``.
          In particular, if `R` is a commutative ring (e.g. a field),
          some pieces of the code possibly assume that `M` is a
          *symmetric `R`-`R`-bimodule*:

          .. MATH::

              r*x = x*r \qquad  \forall r \in R \text{ and } x \in M

        - Make sure that non symmetric modules are properly supported
          by all the code, and advertise it.

        - Make sure that non commutative rings are properly supported
          by all the code, and advertise it.

        - Add support for base semirings.

        - Implement a ``FreeModules(R)`` category, when so prompted by a
          concrete use case: e.g.  modeling a free module with several
          bases (using :meth:`Sets.SubcategoryMethods.Realizations`)
          or with an atlas of local maps (see e.g. :trac:`15916`).
    """

    @staticmethod
    def __classcall_private__(cls, base_ring, dispatch = True):
        r"""
        Implement the dispatching of ``Modules(field)`` to
        ``VectorSpaces(field)``.

        This feature will later be extended, probably as a covariant
        functorial construction, to support modules over various kinds
        of rings (principal ideal domains, ...), or even over semirings.

        TESTS::

            sage: C = Modules(ZZ); C
            Category of modules over Integer Ring
            sage: C is Modules(ZZ, dispatch = False)
            True
            sage: C is Modules(ZZ, dispatch = True)
            True
            sage: C._reduction
            (<class 'sage.categories.modules.Modules'>, (Integer Ring,), {'dispatch': False})
            sage: TestSuite(C).run()

            sage: Modules(QQ) is VectorSpaces(QQ)
            True
            sage: Modules(QQ, dispatch = True) is VectorSpaces(QQ)
            True

            sage: C = Modules(NonNegativeIntegers()); C   # todo: not implemented
            Category of semiring modules over Non negative integers

            sage: C = Modules(QQ, dispatch = False); C
            Category of modules over Rational Field
            sage: C._reduction
            (<class 'sage.categories.modules.Modules'>, (Rational Field,), {'dispatch': False})
            sage: TestSuite(C).run()
        """
        if dispatch:
            if base_ring in _Fields or (isinstance(base_ring, Category)
                                        and base_ring.is_subcategory(_Fields)):
                from .vector_spaces import VectorSpaces
                return VectorSpaces(base_ring, check=False)
        result = super(Modules, cls).__classcall__(cls, base_ring)
        result._reduction[2]['dispatch'] = False
        return result

    def super_categories(self):
        """
        EXAMPLES::

            sage: Modules(ZZ).super_categories()
            [Category of bimodules over Integer Ring on the left and Integer Ring on the right]

        Nota bene::

            sage: Modules(QQ)
            Category of vector spaces over Rational Field
            sage: Modules(QQ).super_categories()
            [Category of modules over Rational Field]
        """
        R = self.base_ring()
        return [Bimodules(R,R)]

    def additional_structure(self):
        r"""
        Return ``None``.

        Indeed, the category of modules defines no additional structure:
        a bimodule morphism between two modules is a module morphism.

        .. SEEALSO:: :meth:`Category.additional_structure`

        .. TODO:: Should this category be a :class:`~sage.categories.category_with_axiom.CategoryWithAxiom`?

        EXAMPLES::

            sage: Modules(ZZ).additional_structure()
        """
        return None

    class SubcategoryMethods:

        @cached_method
        def base_ring(self):
            r"""
            Return the base ring (category) for ``self``.

            This implements a ``base_ring`` method for all
            subcategories of ``Modules(K)``.

            EXAMPLES::

                sage: C = Modules(QQ) & Semigroups(); C
                Join of Category of semigroups and Category of vector spaces over Rational Field
                sage: C.base_ring()
                Rational Field
                sage: C.base_ring.__module__
                'sage.categories.modules'

                sage: C = Modules(Rings()) & Semigroups(); C
                Join of Category of semigroups and Category of modules over rings
                sage: C.base_ring()
                Category of rings
                sage: C.base_ring.__module__
                'sage.categories.modules'

                sage: C = DescentAlgebra(QQ,3).B().category()
                sage: C.base_ring.__module__
                'sage.categories.modules'
                sage: C.base_ring()
                Rational Field

                sage: C = QuasiSymmetricFunctions(QQ).F().category()
                sage: C.base_ring.__module__
                'sage.categories.modules'
                sage: C.base_ring()
                Rational Field
            """
            for C in self.super_categories():
                # Is there a better way to ask if C is a subcategory of Modules?
                if hasattr(C, "base_ring"):
                    return C.base_ring()
            assert False, "some super category of {} should be a category over base ring".format(self)

        def TensorProducts(self):
            r"""
            Return the full subcategory of objects of ``self`` constructed
            as tensor products.

            .. SEEALSO::

                - :class:`.tensor.TensorProductsCategory`
                - :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`.

            EXAMPLES::

                sage: ModulesWithBasis(QQ).TensorProducts()
                Category of tensor products of vector spaces with basis over Rational Field
            """
            return TensorProductsCategory.category_of(self)

        @cached_method
        def DualObjects(self):
            r"""
            Return the category of spaces constructed as duals of
            spaces of ``self``.

            The *dual* of a vector space `V` is the space consisting of
            all linear functionals on `V` (see :wikipedia:`Dual_space`).
            Additional structure on `V` can endow its dual with
            additional structure; for example, if `V` is a finite
            dimensional algebra, then its dual is a coalgebra.

            This returns the category of spaces constructed as dual of
            spaces in ``self``, endowed with the appropriate
            additional structure.

            .. WARNING::

                - This semantic of ``dual`` and ``DualObject`` is
                  imposed on all subcategories, in particular to make
                  ``dual`` a covariant functorial construction.

                  A subcategory that defines a different notion of
                  dual needs to use a different name.

                - Typically, the category of graded modules should
                  define a separate ``graded_dual`` construction (see
                  :trac:`15647`). For now the two constructions are
                  not distinguished which is an oversimplified model.

            .. SEEALSO::

                - :class:`.dual.DualObjectsCategory`
                - :class:`~.covariant_functorial_construction.CovariantFunctorialConstruction`.

            EXAMPLES::

                sage: VectorSpaces(QQ).DualObjects()
                Category of duals of vector spaces over Rational Field

            The dual of a vector space is a vector space::

                sage: VectorSpaces(QQ).DualObjects().super_categories()
                [Category of vector spaces over Rational Field]

            The dual of an algebra is a coalgebra::

                sage: sorted(Algebras(QQ).DualObjects().super_categories(), key=str)
                [Category of coalgebras over Rational Field,
                 Category of duals of vector spaces over Rational Field]

            The dual of a coalgebra is an algebra::

                sage: sorted(Coalgebras(QQ).DualObjects().super_categories(), key=str)
                [Category of algebras over Rational Field,
                 Category of duals of vector spaces over Rational Field]

            As a shorthand, this category can be accessed with the
            :meth:`~Modules.SubcategoryMethods.dual` method::

                sage: VectorSpaces(QQ).dual()
                Category of duals of vector spaces over Rational Field

            TESTS::

                sage: C = VectorSpaces(QQ).DualObjects()
                sage: C.base_category()
                Category of vector spaces over Rational Field
                sage: C.super_categories()
                [Category of vector spaces over Rational Field]
                sage: latex(C)
                \mathbf{DualObjects}(\mathbf{VectorSpaces}_{\Bold{Q}})
                sage: TestSuite(C).run()
            """
            return DualObjectsCategory.category_of(self)

        dual = DualObjects

        @cached_method
        def FiniteDimensional(self):
            r"""
            Return the full subcategory of the finite dimensional objects of ``self``.

            EXAMPLES::

                sage: Modules(ZZ).FiniteDimensional()
                Category of finite dimensional modules over Integer Ring
                sage: Coalgebras(QQ).FiniteDimensional()
                Category of finite dimensional coalgebras over Rational Field
                sage: AlgebrasWithBasis(QQ).FiniteDimensional()
                Category of finite dimensional algebras with basis over Rational Field

            TESTS::

                sage: TestSuite(Modules(ZZ).FiniteDimensional()).run()
                sage: Coalgebras(QQ).FiniteDimensional.__module__
                'sage.categories.modules'
            """
            return self._with_axiom("FiniteDimensional")

        @cached_method
        def Filtered(self, base_ring=None):
            r"""
            Return the subcategory of the filtered objects of ``self``.

            INPUT:

            - ``base_ring`` -- this is ignored

            EXAMPLES::

                sage: Modules(ZZ).Filtered()
                Category of filtered modules over Integer Ring

                sage: Coalgebras(QQ).Filtered()
                Category of filtered coalgebras over Rational Field

                sage: AlgebrasWithBasis(QQ).Filtered()
                Category of filtered algebras with basis over Rational Field

            .. TODO::

                - Explain why this does not commute with :meth:`WithBasis`
                - Improve the support for covariant functorial
                  constructions categories over a base ring so as to
                  get rid of the ``base_ring`` argument.

            TESTS::

                sage: Coalgebras(QQ).Graded.__module__
                'sage.categories.modules'
            """
            assert base_ring is None or base_ring is self.base_ring()
            from sage.categories.filtered_modules import FilteredModulesCategory
            return FilteredModulesCategory.category_of(self)

        @cached_method
        def Graded(self, base_ring=None):
            r"""
            Return the subcategory of the graded objects of ``self``.

            INPUT:

            - ``base_ring`` -- this is ignored

            EXAMPLES::

                sage: Modules(ZZ).Graded()
                Category of graded modules over Integer Ring

                sage: Coalgebras(QQ).Graded()
                Category of graded coalgebras over Rational Field

                sage: AlgebrasWithBasis(QQ).Graded()
                Category of graded algebras with basis over Rational Field

            .. TODO::

                - Explain why this does not commute with :meth:`WithBasis`
                - Improve the support for covariant functorial
                  constructions categories over a base ring so as to
                  get rid of the ``base_ring`` argument.

            TESTS::

                sage: Coalgebras(QQ).Graded.__module__
                'sage.categories.modules'
            """
            assert base_ring is None or base_ring is self.base_ring()
            from sage.categories.graded_modules import GradedModulesCategory
            return GradedModulesCategory.category_of(self)

        @cached_method
        def Super(self, base_ring=None):
            r"""
            Return the super-analogue category of ``self``.

            INPUT:

            - ``base_ring`` -- this is ignored

            EXAMPLES::

                sage: Modules(ZZ).Super()
                Category of super modules over Integer Ring

                sage: Coalgebras(QQ).Super()
                Category of super coalgebras over Rational Field

                sage: AlgebrasWithBasis(QQ).Super()
                Category of super algebras with basis over Rational Field

            .. TODO::

                - Explain why this does not commute with :meth:`WithBasis`
                - Improve the support for covariant functorial
                  constructions categories over a base ring so as to
                  get rid of the ``base_ring`` argument.

            TESTS::

                sage: Coalgebras(QQ).Super.__module__
                'sage.categories.modules'
            """
            assert base_ring is None or base_ring is self.base_ring()
            from sage.categories.super_modules import SuperModulesCategory
            return SuperModulesCategory.category_of(self)

        @cached_method
        def WithBasis(self):
            r"""
            Return the full subcategory of the objects of ``self`` with
            a distinguished basis.

            EXAMPLES::

                sage: Modules(ZZ).WithBasis()
                Category of modules with basis over Integer Ring
                sage: Coalgebras(QQ).WithBasis()
                Category of coalgebras with basis over Rational Field
                sage: AlgebrasWithBasis(QQ).WithBasis()
                Category of algebras with basis over Rational Field

            TESTS::

                sage: TestSuite(Modules(ZZ).WithBasis()).run()
                sage: Coalgebras(QQ).WithBasis.__module__
                'sage.categories.modules'
            """
            return self._with_axiom("WithBasis")

    class FiniteDimensional(CategoryWithAxiom_over_base_ring):

        def extra_super_categories(self):
            """
            Implement the fact that a finite dimensional module over a finite
            ring is finite.

            EXAMPLES::

                sage: Modules(IntegerModRing(4)).FiniteDimensional().extra_super_categories()
                [Category of finite sets]
                sage: Modules(ZZ).FiniteDimensional().extra_super_categories()
                []
                sage: Modules(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite())
                True
                sage: Modules(ZZ).FiniteDimensional().is_subcategory(Sets().Finite())
                False

                sage: Modules(Rings().Finite()).FiniteDimensional().is_subcategory(Sets().Finite())
                True
                sage: Modules(Rings()).FiniteDimensional().is_subcategory(Sets().Finite())
                False
            """
            base_ring = self.base_ring()
            FiniteSets = Sets().Finite()
            if (isinstance(base_ring, Category) and
                    base_ring.is_subcategory(FiniteSets)) or \
                base_ring in FiniteSets:
                return [FiniteSets]
            else:
                return []

    Filtered = LazyImport('sage.categories.filtered_modules', 'FilteredModules')
    Graded = LazyImport('sage.categories.graded_modules', 'GradedModules')
    Super = LazyImport('sage.categories.super_modules', 'SuperModules')
    # at_startup currently needed for MatrixSpace, see #22955 (e.g., comment:20)
    WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis',
                           at_startup=True)

    class ParentMethods:
        @cached_method
        def tensor_square(self):
            """
            Returns the tensor square of ``self``

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example()
                sage: A.tensor_square()
                An example of Hopf algebra with basis:
                 the group algebra of the Dihedral group of order 6
                 as a permutation group over Rational Field # An example
                 of Hopf algebra with basis: the group algebra of the Dihedral
                 group of order 6 as a permutation group over Rational Field
            """
            return tensor([self, self])

    class ElementMethods:
        pass

    class Homsets(HomsetsCategory):
        r"""
        The category of homomorphism sets `\hom(X,Y)` for `X`, `Y` modules.
        """

        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Modules(ZZ).Homsets().extra_super_categories()
                [Category of modules over Integer Ring]
            """
            return [Modules(self.base_category().base_ring())]

        def base_ring(self):
            """
            EXAMPLES::

                sage: Modules(ZZ).Homsets().base_ring()
                Integer Ring

            .. TODO::

                Generalize this so that any homset category of a full
                subcategory of modules over a base ring is a category over
                this base ring.
            """
            return self.base_category().base_ring()

        class ParentMethods:

            @cached_method
            def base_ring(self):
                """
                Return the base ring of ``self``.

                EXAMPLES::

                    sage: E = CombinatorialFreeModule(ZZ, [1,2,3])
                    sage: F = CombinatorialFreeModule(ZZ, [2,3,4])
                    sage: H = Hom(E, F)
                    sage: H.base_ring()
                    Integer Ring

                This ``base_ring`` method is actually overridden by
                :meth:`sage.structure.category_object.CategoryObject.base_ring`::

                    sage: H.base_ring.__module__

                Here we call it directly::

                    sage: method = H.category().parent_class.base_ring
                    sage: method.__get__(H)()
                    Integer Ring
                """
                return self.domain().base_ring()

            @cached_method
            def zero(self):
                """
                EXAMPLES::

                    sage: E = CombinatorialFreeModule(ZZ, [1,2,3])
                    sage: F = CombinatorialFreeModule(ZZ, [2,3,4])
                    sage: H = Hom(E, F)
                    sage: f = H.zero()
                    sage: f
                    Generic morphism:
                      From: Free module generated by {1, 2, 3} over Integer Ring
                      To:   Free module generated by {2, 3, 4} over Integer Ring
                    sage: f(E.monomial(2))
                    0
                    sage: f(E.monomial(3)) == F.zero()
                    True

                TESTS:

                We check that ``H.zero()`` is picklable::

                    sage: loads(dumps(f.parent().zero()))
                    Generic morphism:
                      From: Free module generated by {1, 2, 3} over Integer Ring
                      To:   Free module generated by {2, 3, 4} over Integer Ring
                """
                from sage.misc.constant_function import ConstantFunction
                return self(ConstantFunction(self.codomain().zero()))

        class Endset(CategoryWithAxiom_over_base_ring):
            """
            The category of endomorphism sets `End(X)` for `X`
            a module (this is not used yet)
            """
            def extra_super_categories(self):
                """
                Implement the fact that the endomorphism set of a module is an algebra.

                .. SEEALSO:: :meth:`CategoryWithAxiom.extra_super_categories`

                EXAMPLES::

                    sage: Modules(ZZ).Endsets().extra_super_categories()
                    [Category of magmatic algebras over Integer Ring]

                    sage: End(ZZ^3) in Algebras(ZZ)
                    True
                """
                from .magmatic_algebras import MagmaticAlgebras
                return [MagmaticAlgebras(self.base_category().base_ring())]

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of modules constructed as Cartesian products of modules

        This construction gives the direct product of modules. The
        implementation is based on the following resources:

        - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16
        - :wikipedia:`Direct_product`
        """
        def extra_super_categories(self):
            """
            A Cartesian product of modules is endowed with a natural
            module structure.

            EXAMPLES::

                sage: Modules(ZZ).CartesianProducts().extra_super_categories()
                [Category of modules over Integer Ring]
                sage: Modules(ZZ).CartesianProducts().super_categories()
                [Category of Cartesian products of commutative additive groups,
                 Category of modules over Integer Ring]
            """
            return [self.base_category()]

        class ParentMethods:
            def base_ring(self):
                """
                Return the base ring of this Cartesian product.

                EXAMPLES::

                    sage: E = CombinatorialFreeModule(ZZ, [1,2,3])
                    sage: F = CombinatorialFreeModule(ZZ, [2,3,4])
                    sage: C = cartesian_product([E, F]); C
                    Free module generated by {1, 2, 3} over Integer Ring (+)
                    Free module generated by {2, 3, 4} over Integer Ring
                    sage: C.base_ring()
                    Integer Ring
                """
                return self._sets[0].base_ring()

    class TensorProducts(TensorProductsCategory):
        """
        The category of modules constructed by tensor product of modules.
        """
        @cached_method
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Modules(ZZ).TensorProducts().extra_super_categories()
                [Category of modules over Integer Ring]
                sage: Modules(ZZ).TensorProducts().super_categories()
                [Category of modules over Integer Ring]
            """
            return [self.base_category()]
Ejemplo n.º 6
0
class Monoids(CategoryWithAxiom):
    r"""
    The category of (multiplicative) monoids.

    A *monoid* is a unital :class:`semigroup <Semigroups>`, that is a
    set endowed with a multiplicative binary operation `*` which is
    associative and admits a unit (see :wikipedia:`Monoid`).

    EXAMPLES::

        sage: Monoids()
        Category of monoids
        sage: Monoids().super_categories()
        [Category of semigroups, Category of unital magmas]
        sage: Monoids().all_super_categories()
        [Category of monoids,
         Category of semigroups,
         Category of unital magmas, Category of magmas,
         Category of sets,
         Category of sets with partial maps,
         Category of objects]

        sage: Monoids().axioms()
        frozenset(['Associative', 'Unital'])
        sage: Semigroups().Unital()
        Category of monoids

        sage: Monoids().example()
        An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd')

    TESTS::

        sage: C = Monoids()
        sage: TestSuite(C).run()

    """

    _base_category_class_and_axiom = (Semigroups, "Unital")

    Finite = LazyImport('sage.categories.finite_monoids',
                        'FiniteMonoids',
                        at_startup=True)
    Inverse = LazyImport('sage.categories.groups', 'Groups', at_startup=True)

    @staticmethod
    def free(index_set=None, names=None, **kwds):
        r"""
        Return a free monoid on `n` generators or with the generators
        indexed by a set `I`.

        A free monoid is constructed by specifing either:

        - the number of generators and/or the names of the generators
        - the indexing set for the generators

        INPUT:

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

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

        EXAMPLES::

            sage: Monoids.free(index_set=ZZ)
            Free monoid indexed by Integer Ring
            sage: Monoids().free(ZZ)
            Free monoid indexed by Integer Ring
            sage: F.<x,y,z> = Monoids().free(); F
            Free monoid indexed by {'x', 'y', 'z'}
        """
        if names is not None:
            if isinstance(names, str):
                from sage.rings.all import ZZ
                if ',' not in names and index_set in ZZ:
                    names = [names + repr(i) for i in range(index_set)]
                else:
                    names = names.split(',')
            names = tuple(names)
            if index_set is None:
                index_set = names

        from sage.monoids.indexed_free_monoid import IndexedFreeMonoid
        return IndexedFreeMonoid(index_set, names=names, **kwds)

    class ParentMethods:
        def one_element(self):
            r"""
            Backward compatibility alias for :meth:`one`.

            TESTS::

                sage: S = Monoids().example()
                sage: S.one_element()
                ''

            """
            return self.one()

        def prod(self, args):
            r"""
            n-ary product of elements of ``self``.

            INPUT:

            - ``args`` -- a list (or iterable) of elements of ``self``

            Returns the product of the elements in ``args``, as an element of
            ``self``.

            EXAMPLES::

                sage: S = Monoids().example()
                sage: S.prod([S('a'), S('b')])
                'ab'
            """
            return prod(args, self.one())

        def _test_prod(self, **options):
            r"""
            Run basic tests for the product method :meth:`prod` of ``self``.

            See the documentation for :class:`TestSuite` for information on
            further options.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`

            EXAMPLES:

            By default, this method tests only the elements returned by
            ``self.some_elements()``::

                sage: S = Monoids().example()
                sage: S._test_prod()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: S._test_prod(elements = (S('a'), S('b')))
            """
            tester = self._tester(**options)
            tester.assert_(self.prod([]) == self.one())
            for x in tester.some_elements():
                tester.assert_(self.prod([x]) == x)
                tester.assert_(self.prod([x, x]) == x**2)
                tester.assert_(self.prod([x, x, x]) == x**3)

    class ElementMethods:
        def is_one(self):
            r"""
            Return whether ``self`` is the one of the monoid.

            The default implementation is to compare with ``self.one()``.

            TESTS::

                sage: S = Monoids().example()
                sage: S.one().is_one()
                True
                sage: S("aa").is_one()
                False
            """
            return self == self.parent().one()

        def __pow__(self, n):
            r"""
            Return ``self`` to the `n^{th}` power.

            INPUT:

            - ``n`` -- a nonnegative integer

            EXAMPLES::

                sage: S = Monoids().example()
                sage: x = S("aa")
                sage: x^0, x^1, x^2, x^3, x^4, x^5
                ('', 'aa', 'aaaa', 'aaaaaa', 'aaaaaaaa', 'aaaaaaaaaa')

            """
            if not n:  # FIXME: why do we need to do that?
                return self.parent().one()
            return generic_power(self, n, self.parent().one())

        def _pow_naive(self, n):
            r"""
            Return ``self`` to the `n^{th}` power (naive implementation).

            INPUT:

            - ``n`` -- a nonnegative integer

            This naive implementation does not use binary
            exponentiation; there are cases where this is actually
            faster due to size explosion.

            EXAMPLES::

                sage: S = Monoids().example()
                sage: x = S("aa")
                sage: [x._pow_naive(i) for i in range(6)]
                ['', 'aa', 'aaaa', 'aaaaaa', 'aaaaaaaa', 'aaaaaaaaaa']
            """
            if not n:
                return self.parent().one()
            result = self
            for i in range(n - 1):
                result *= self
            return result

    class Commutative(CategoryWithAxiom):
        """
        Category of commutative (abelian) monoids.

        A monoid `M` is *commutative* if `xy = yx` for all `x,y \in M`.
        """
        @staticmethod
        def free(index_set=None, names=None, **kwds):
            r"""
            Return a free abelian monoid on `n` generators or with
            the generators indexed by a set `I`.

            A free monoid is constructed by specifing either:

            - the number of generators and/or the names of the generators, or
            - the indexing set for the generators.

            INPUT:

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

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

            EXAMPLES::

                sage: Monoids.Commutative.free(index_set=ZZ)
                Free abelian monoid indexed by Integer Ring
                sage: Monoids().Commutative().free(ZZ)
                Free abelian monoid indexed by Integer Ring
                sage: F.<x,y,z> = Monoids().Commutative().free(); F
                Free abelian monoid indexed by {'x', 'y', 'z'}
            """
            if names is not None:
                if isinstance(names, str):
                    from sage.rings.all import ZZ
                    if ',' not in names and index_set in ZZ:
                        names = [names + repr(i) for i in range(index_set)]
                    else:
                        names = names.split(',')
                names = tuple(names)
                if index_set is None:
                    index_set = names

            from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid
            return IndexedFreeAbelianMonoid(index_set, names=names, **kwds)

    class WithRealizations(WithRealizationsCategory):
        class ParentMethods:
            def one(self):
                r"""
                Return the unit of this monoid.

                This default implementation returns the unit of the
                realization of ``self`` given by
                :meth:`~Sets.WithRealizations.ParentMethods.a_realization`.

                EXAMPLES::

                    sage: A = Sets().WithRealizations().example(); A
                    The subset algebra of {1, 2, 3} over Rational Field
                    sage: A.one.__module__
                    'sage.categories.monoids'
                    sage: A.one()
                    F[{}]

                TESTS::

                    sage: A.one() is A.a_realization().one()
                    True
                    sage: A._test_one()
                """
                return self.a_realization().one()

    class Subquotients(SubquotientsCategory):
        class ParentMethods:
            def one(self):
                """
                Returns the multiplicative unit of this monoid,
                obtained by retracting that of the ambient monoid.

                EXAMPLES::

                    sage: S = Monoids().Subquotients().example() # todo: not implemented
                    sage: S.one()                                # todo: not implemented
                """
                return self.retract(self.ambient().one())

    class Algebras(AlgebrasCategory):
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Monoids().Algebras(QQ).extra_super_categories()
                [Category of monoids]
                sage: Monoids().Algebras(QQ).super_categories()
                [Category of algebras with basis over Rational Field,
                 Category of semigroup algebras over Rational Field,
                 Category of unital magma algebras over Rational Field]
            """
            return [Monoids()]

        class ParentMethods:
            @cached_method
            def one_basis(self):
                """
                Return the unit of the monoid, which indexes the unit of
                this algebra, as per
                :meth:`AlgebrasWithBasis.ParentMethods.one_basis()
                <sage.categories.algebras_with_basis.AlgebrasWithBasis.ParentMethods.one_basis>`.

                EXAMPLES::

                    sage: A = Monoids().example().algebra(ZZ)
                    sage: A.one_basis()
                    ''
                    sage: A.one()
                    B['']
                    sage: A(3)
                    3*B['']
                """
                return self.basis().keys().one()

        class ElementMethods:
            def is_central(self):
                r"""
                Return whether the element ``self`` is central.

                EXAMPLES::

                    sage: SG4=SymmetricGroupAlgebra(ZZ,4)
                    sage: SG4(1).is_central()
                    True
                    sage: SG4(Permutation([1,3,2,4])).is_central()
                    False
                    sage: A=GroupAlgebras(QQ).example(); A
                    Group algebra of Dihedral group of order 8 as a permutation group over Rational Field
                    sage: sum(i for i in A.basis()).is_central()
                    True
                """
                return all([
                    i * self == self * i
                    for i in self.parent().algebra_generators()
                ])

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of monoids constructed as cartesian products of monoids.

        This construction gives the direct product of monoids. See
        :wikipedia:`Direct_product` for more information.
        """
        def extra_super_categories(self):
            """
            A cartesian product of monoids is endowed with a natural
            group structure.

            EXAMPLES::

                sage: C = Monoids().CartesianProducts()
                sage: C.extra_super_categories()
                [Category of monoids]
                sage: sorted(C.super_categories(), key=str)
                [Category of Cartesian products of semigroups,
                 Category of Cartesian products of unital magmas,
                 Category of monoids]
            """
            return [self.base_category()]

        class ParentMethods:
            @cached_method
            def monoid_generators(self):
                """
                Return the generators of ``self``.

                EXAMPLES::

                    sage: M = Monoids.free([1,2,3])
                    sage: N = Monoids.free(['a','b'])
                    sage: C = cartesian_product([M, N])
                    sage: C.monoid_generators()
                    Family ((F[1], 1), (F[2], 1), (F[3], 1),
                            (1, F['a']), (1, F['b']))

                An example with an infinitely generated group (a better output
                is needed)::

                    sage: N = Monoids.free(ZZ)
                    sage: C = cartesian_product([M, N])
                    sage: C.monoid_generators()
                    Lazy family (gen(i))_{i in The cartesian product of (...)}
                """
                F = self.cartesian_factors()
                ids = tuple(M.one() for M in F)

                def lift(i, gen):
                    cur = list(ids)
                    cur[i] = gen
                    return self._cartesian_product_of_elements(cur)

                from sage.sets.family import Family

                # Finitely generated
                cat = FiniteEnumeratedSets()
                if all(M.monoid_generators() in cat
                       or isinstance(M.monoid_generators(), (tuple, list))
                       for M in F):
                    ret = [
                        lift(i, gen) for i, M in enumerate(F)
                        for gen in M.monoid_generators()
                    ]
                    return Family(ret)

                # Infinitely generated
                # This does not return a good output, but it is "correct"
                # TODO: Figure out a better way to do things
                gens_prod = cartesian_product([
                    Family(M.monoid_generators(), lambda g: (i, g))
                    for i, M in enumerate(F)
                ])
                return Family(gens_prod, lift, name="gen")
Ejemplo n.º 7
0
class Rings(CategoryWithAxiom):
    """
    The category of rings

    Associative rings with unit, not necessarily commutative

    EXAMPLES::

        sage: Rings()
        Category of rings
        sage: sorted(Rings().super_categories(), key=str)
        [Category of rngs, Category of semirings]

        sage: sorted(Rings().axioms())
        ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveInverse',
         'AdditiveUnital', 'Associative', 'Distributive', 'Unital']

        sage: Rings() is (CommutativeAdditiveGroups() & Monoids()).Distributive()
        True
        sage: Rings() is Rngs().Unital()
        True
        sage: Rings() is Semirings().AdditiveInverse()
        True

    TESTS::

        sage: TestSuite(Rings()).run()

    .. TODO::

        (see: http://trac.sagemath.org/sage_trac/wiki/CategoriesRoadMap)

        - Make Rings() into a subcategory or alias of Algebras(ZZ);

        - A parent P in the category ``Rings()`` should automatically be
          in the category ``Algebras(P)``.
    """

    _base_category_class_and_axiom = (Rngs, "Unital")

    class MorphismMethods:
        @cached_method
        def is_injective(self):
            """
            Return whether or not this morphism is injective.

            EXAMPLES::

                sage: R.<x,y> = QQ[]
                sage: R.hom([x, y^2], R).is_injective()
                True
                sage: R.hom([x, x^2], R).is_injective()
                False
                sage: S.<u,v> = R.quotient(x^3*y)
                sage: R.hom([v, u], S).is_injective()
                False
                sage: S.hom([-u, v], S).is_injective()
                True
                sage: S.cover().is_injective()
                False

            If the domain is a field, the homomorphism is injective::

                sage: K.<x> = FunctionField(QQ)
                sage: L.<y> = FunctionField(QQ)
                sage: f = K.hom([y]); f
                Function Field morphism:
                  From: Rational function field in x over Rational Field
                  To:   Rational function field in y over Rational Field
                  Defn: x |--> y
                sage: f.is_injective()
                True

            Unless the codomain is the zero ring::

                sage: codomain = Integers(1)
                sage: f = QQ.hom([Zmod(1)(0)], check=False)
                sage: f.is_injective()
                False

            Homomorphism from rings of characteristic zero to rings of positive
            characteristic can not be injective::

                sage: R.<x> = ZZ[]
                sage: f = R.hom([GF(3)(1)]); f
                Ring morphism:
                  From: Univariate Polynomial Ring in x over Integer Ring
                  To:   Finite Field of size 3
                  Defn: x |--> 1
                sage: f.is_injective()
                False

            A morphism whose domain is an order in a number field is injective if
            the codomain has characteristic zero::

                sage: K.<x> = FunctionField(QQ)
                sage: f = ZZ.hom(K); f
                Composite map:
                  From: Integer Ring
                  To:   Rational function field in x over Rational Field
                  Defn:   Conversion via FractionFieldElement_1poly_field map:
                          From: Integer Ring
                          To:   Fraction Field of Univariate Polynomial Ring in x over Rational Field
                        then
                          Isomorphism:
                          From: Fraction Field of Univariate Polynomial Ring in x over Rational Field
                          To:   Rational function field in x over Rational Field
                sage: f.is_injective()
                True

            A coercion to the fraction field is injective::

                sage: R = ZpFM(3)
                sage: R.fraction_field().coerce_map_from(R).is_injective()
                True

            """
            if self.domain().is_zero():
                return True
            if self.codomain().is_zero():
                # the only map to the zero ring that is injective is the map from itself
                return False

            from sage.categories.fields import Fields
            if self.domain() in Fields():
                # A ring homomorphism from a field to a ring is injective
                # (unless the codomain is the zero ring.) Note that ring
                # homomorphism must send the 1 element to the 1 element
                return True

            try:
                ker = self.kernel()
            except (NotImplementedError, AttributeError):
                pass
            else:
                return ker.is_zero()

            if self.domain().characteristic() == 0:
                if self.codomain().characteristic() != 0:
                    return False
                else:
                    from sage.categories.integral_domains import IntegralDomains
                    if self.domain() in IntegralDomains():
                        # if all elements of the domain are algebraic over ZZ,
                        # then the homomorphism must be injective (in
                        # particular if the domain is ZZ)
                        from sage.categories.number_fields import NumberFields
                        if self.domain().fraction_field() in NumberFields():
                            return True

            if self._is_coercion:
                try:
                    K = self.domain().fraction_field()
                except (TypeError, AttributeError, ValueError):
                    pass
                else:
                    if K is self.codomain():
                        return True

            try:
                if self.domain().cardinality() > self.codomain().cardinality():
                    return False
            except AttributeError:
                pass

            raise NotImplementedError

        def _is_nonzero(self):
            r"""
            Return whether this is not the zero morphism.

            .. NOTE::

                We can not override ``is_zero()`` from the category framework
                and we can not implement ``__nonzero__`` because it is a
                special method. That this is why this has a cumbersome name.

            EXAMPLES::

                sage: ZZ.hom(ZZ)._is_nonzero()
                True
                sage: ZZ.hom(Zmod(1))._is_nonzero()
                False

            """
            return bool(self.codomain().one())

        def extend_to_fraction_field(self):
            r"""
            Return the extension of this morphism to fraction fields of
            the domain and the codomain.

            EXAMPLES::

                sage: S.<x> = QQ[]
                sage: f = S.hom([x+1]); f
                Ring endomorphism of Univariate Polynomial Ring in x over Rational Field
                    Defn: x |--> x + 1

                sage: g = f.extend_to_fraction_field(); g
                Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Rational Field
                    Defn: x |--> x + 1
                sage: g(x)
                x + 1
                sage: g(1/x)
                1/(x + 1)

            If this morphism is not injective, it does not extend to the fraction
            field and an error is raised::

                sage: f = GF(5).coerce_map_from(ZZ)
                sage: f.extend_to_fraction_field()
                Traceback (most recent call last):
                ...
                ValueError: the morphism is not injective

            TESTS::

                sage: A.<x> = RR[]
                sage: phi = A.hom([x+1])
                sage: phi.extend_to_fraction_field()
                Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Real Field with 53 bits of precision
                  Defn: x |--> x + 1.00000000000000
            """
            from sage.rings.morphism import RingHomomorphism_from_fraction_field
            if self.domain().is_field() and self.codomain().is_field():
                return self
            try:
                if not self.is_injective():
                    raise ValueError("the morphism is not injective")
            except (NotImplementedError, TypeError):  # we trust the user
                pass
            domain = self.domain().fraction_field()
            codomain = self.codomain().fraction_field()
            parent = domain.Hom(
                codomain)  # category = category=self.category_for() ???
            return RingHomomorphism_from_fraction_field(parent, self)

    class SubcategoryMethods:
        def NoZeroDivisors(self):
            r"""
            Return the full subcategory of the objects of ``self`` having
            no nonzero zero divisors.

            A *zero divisor* in a ring `R` is an element `x \in R` such
            that there exists a nonzero element `y \in R` such that
            `x \cdot y = 0` or `y \cdot x = 0`
            (see :wikipedia:`Zero_divisor`).

            EXAMPLES::

                sage: Rings().NoZeroDivisors()
                Category of domains

            .. NOTE::

                This could be generalized to
                :class:`MagmasAndAdditiveMagmas.Distributive.AdditiveUnital`.

            TESTS::

                sage: TestSuite(Rings().NoZeroDivisors()).run()
                sage: Algebras(QQ).NoZeroDivisors.__module__
                'sage.categories.rings'
            """
            return self._with_axiom('NoZeroDivisors')

        def Division(self):
            """
            Return the full subcategory of the division objects of ``self``.

            A ring satisfies the *division axiom* if all non-zero
            elements have multiplicative inverses.

            .. NOTE::

                This could be generalized to
                :class:`MagmasAndAdditiveMagmas.Distributive.AdditiveUnital`.

            EXAMPLES::

                sage: Rings().Division()
                Category of division rings
                sage: Rings().Commutative().Division()
                Category of fields

            TESTS::

                sage: TestSuite(Rings().Division()).run()
                sage: Algebras(QQ).Division.__module__
                'sage.categories.rings'
            """
            return self._with_axiom('Division')

    NoZeroDivisors = LazyImport('sage.categories.domains',
                                'Domains',
                                at_startup=True)
    Division = LazyImport('sage.categories.division_rings',
                          'DivisionRings',
                          at_startup=True)
    Commutative = LazyImport('sage.categories.commutative_rings',
                             'CommutativeRings',
                             at_startup=True)

    class ParentMethods:
        def is_ring(self):
            """
            Return True, since this in an object of the category of rings.

            EXAMPLES::

                sage: Parent(QQ,category=Rings()).is_ring()
                True
            """
            return True

        def is_zero(self):
            """
            Return ``True`` if this is the zero ring.

            EXAMPLES::

                sage: Integers(1).is_zero()
                True
                sage: Integers(2).is_zero()
                False
                sage: QQ.is_zero()
                False
                sage: R.<x> = ZZ[]
                sage: R.quo(1).is_zero()
                True
                sage: R.<x> = GF(101)[]
                sage: R.quo(77).is_zero()
                True
                sage: R.quo(x^2+1).is_zero()
                False
            """
            return self.one() == self.zero()

        def bracket(self, x, y):
            """
            Returns the Lie bracket `[x, y] = x y - y x` of `x` and `y`.

            INPUT:

             - ``x``, ``y`` -- elements of ``self``

            EXAMPLES::

                sage: F = AlgebrasWithBasis(QQ).example()
                sage: F
                An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                sage: a,b,c = F.algebra_generators()
                sage: F.bracket(a,b)
                B[word: ab] - B[word: ba]

            This measures the default of commutation between `x` and `y`.
            `F` endowed with the bracket operation is a Lie algebra;
            in particular, it satisfies Jacobi's identity::

                sage: F.bracket( F.bracket(a,b), c) + F.bracket(F.bracket(b,c),a) + F.bracket(F.bracket(c,a),b)
                0
            """
            return x * y - y * x

        def _Hom_(self, Y, category):
            r"""
            Returns the homset from ``self`` to ``Y`` in the category ``category``

            INPUT:

            - ``Y`` -- a ring
            - ``category`` -- a subcategory of :class:`Rings`() or None

            The sole purpose of this method is to construct the homset
            as a :class:`~sage.rings.homset.RingHomset`. If
            ``category`` is specified and is not a subcategory of
            :class:`Rings`, a ``TypeError`` is raised instead

            This method is not meant to be called directly. Please use
            :func:`sage.categories.homset.Hom` instead.

            EXAMPLES::

                sage: H = QQ._Hom_(QQ, category = Rings()); H
                Set of Homomorphisms from Rational Field to Rational Field
                sage: H.__class__
                <class 'sage.rings.homset.RingHomset_generic_with_category'>

            TESTS::

                sage: Hom(QQ, QQ, category = Rings()).__class__
                <class 'sage.rings.homset.RingHomset_generic_with_category'>

                sage: Hom(CyclotomicField(3), QQ, category = Rings()).__class__
                <class 'sage.rings.number_field.homset.CyclotomicFieldHomset_with_category'>

                sage: TestSuite(Hom(QQ, QQ, category = Rings())).run() # indirect doctest

            """
            if category is not None and not category.is_subcategory(Rings()):
                raise TypeError("%s is not a subcategory of Rings()" %
                                category)
            if Y not in Rings():
                raise TypeError("%s is not a ring" % Y)
            from sage.rings.homset import RingHomset
            return RingHomset(self, Y, category=category)

        # this is already in sage.rings.ring.Ring,
        # but not all rings descend from that class,
        # e.g., matrix spaces.
        def _mul_(self, x, switch_sides=False):
            """
            Multiplication of rings with, e.g., lists.

            NOTE:

            This method is used to create ideals. It is
            the same as the multiplication method for
            :class:`~sage.rings.ring.Ring`. However, not
            all parents that belong to the category of
            rings also inherits from the base class of
            rings. Therefore, we implemented a ``__mul__``
            method for parents, that calls a ``_mul_``
            method implemented here. See :trac:`7797`.

            INPUT:

            - `x`, an object to multiply with.
            - `switch_sides` (optional bool): If ``False``,
              the product is ``self*x``; if ``True``, the
              product is ``x*self``.

            EXAMPLES:

            As we mentioned above, this method is called
            when a ring is involved that does not inherit
            from the base class of rings. This is the case,
            e.g., for matrix algebras::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS*2     # indirect doctest
                Left Ideal
                (
                  [2 0]
                  [0 2]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            In the next example, the ring and the other factor switch sides
            in the product::

                sage: [MS.2]*MS
                Right Ideal
                (
                  [0 0]
                  [1 0]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            AUTHOR:

            - Simon King (2011-03-22)

            """
            try:
                if self.is_commutative():
                    return self.ideal(x)
            except (AttributeError, NotImplementedError):
                pass
            try:
                side = x.side()
            except AttributeError:
                return self.ideal(x, side='right' if switch_sides else 'left')
            # presumably x is an ideal...
            try:
                x = x.gens()
            except (AttributeError, NotImplementedError):
                pass  # ... not an ideal
            if switch_sides:
                if side in ['right', 'twosided']:
                    return self.ideal(x, side=side)
                elif side == 'left':
                    return self.ideal(x, side='twosided')
            else:
                if side in ['left', 'twosided']:
                    return self.ideal(x, side=side)
                elif side == 'right':
                    return self.ideal(x, side='twosided')
            # duck typing failed
            raise TypeError(
                "Don't know how to transform %s into an ideal of %s" %
                (x, self))

        @cached_method
        def ideal_monoid(self):
            """
            The monoid of the ideals of this ring.

            NOTE:

            The code is copied from the base class of rings.
            This is since there are rings that do not inherit
            from that class, such as matrix algebras.  See
            :trac:`7797`.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS.ideal_monoid()
                Monoid of ideals of Full MatrixSpace of 2 by 2 dense matrices
                over Rational Field

            Note that the monoid is cached::

                sage: MS.ideal_monoid() is MS.ideal_monoid()
                True

            """
            try:
                from sage.rings.ideal_monoid import IdealMonoid
                return IdealMonoid(self)
            except TypeError:
                from sage.rings.noncommutative_ideals import IdealMonoid_nc
                return IdealMonoid_nc(self)

        def characteristic(self):
            """
            Return the characteristic of this ring.

            EXAMPLES::

                sage: QQ.characteristic()
                0
                sage: GF(19).characteristic()
                19
                sage: Integers(8).characteristic()
                8
                sage: Zp(5).characteristic()
                0
            """
            from sage.rings.infinity import infinity
            from sage.rings.integer_ring import ZZ
            order_1 = self.one().additive_order()
            return ZZ.zero() if order_1 is infinity else order_1

        def _test_characteristic(self, **options):
            """
            Run generic tests on the method :meth:`characteristic`.

            See also: :class:`TestSuite`.

            EXAMPLES::

                sage: ZZ._test_characteristic()
            """
            tester = self._tester(**options)
            try:
                characteristic = self.characteristic()
            except AttributeError:
                return  # raised when self.one() does not have a additive_order()
            except NotImplementedError:
                return

            # test that #12988 is fixed
            from sage.rings.integer import Integer
            tester.assertIsInstance(characteristic, Integer)

        def ideal(self, *args, **kwds):
            """
            Create an ideal of this ring.

            NOTE:

            The code is copied from the base class
            :class:`~sage.rings.ring.Ring`. This is
            because there are rings that do not inherit
            from that class, such as matrix algebras.
            See :trac:`7797`.

            INPUT:

            - An element or a list/tuple/sequence of elements.
            - ``coerce`` (optional bool, default ``True``):
              First coerce the elements into this ring.
            - ``side``, optional string, one of ``"twosided"``
              (default), ``"left"``, ``"right"``: determines
              whether the resulting ideal is twosided, a left
              ideal or a right ideal.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS.ideal(2)
                Twosided Ideal
                (
                  [2 0]
                  [0 2]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
                sage: MS.ideal([MS.0,MS.1],side='right')
                Right Ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            """
            if 'coerce' in kwds:
                coerce = kwds['coerce']
                del kwds['coerce']
            else:
                coerce = True

            from sage.rings.ideal import Ideal_generic
            from types import GeneratorType
            if len(args) == 0:
                gens = [self(0)]
            else:
                gens = args
                while isinstance(
                        gens, (list, tuple, GeneratorType)) and len(gens) == 1:
                    first = gens[0]
                    if isinstance(first, Ideal_generic):
                        R = first.ring()
                        m = self.convert_map_from(R)
                        if m is not None:
                            gens = [m(g) for g in first.gens()]
                            coerce = False
                        else:
                            m = R.convert_map_from(self)
                            if m is not None:
                                raise NotImplementedError
                            else:
                                raise TypeError
                        break
                    elif isinstance(first, (list, tuple, GeneratorType)):
                        gens = first
                    else:
                        try:
                            if self.has_coerce_map_from(first):
                                gens = first.gens(
                                )  # we have a ring as argument
                            elif isinstance(first, Element):
                                gens = [first]
                            else:
                                raise ArithmeticError(
                                    "There is no coercion from %s to %s" %
                                    (first, self))
                        except TypeError:  # first may be a ring element
                            pass
                        break
            if coerce:
                gens = [self(g) for g in gens]
            from sage.categories.principal_ideal_domains import PrincipalIdealDomains
            if self in PrincipalIdealDomains():
                # Use GCD algorithm to obtain a principal ideal
                g = gens[0]
                if len(gens) == 1:
                    try:
                        g = g.gcd(
                            g
                        )  # note: we set g = gcd(g, g) to "canonicalize" the generator: make polynomials monic, etc.
                    except (AttributeError, NotImplementedError):
                        pass
                else:
                    for h in gens[1:]:
                        g = g.gcd(h)
                gens = [g]
            if 'ideal_class' in kwds:
                C = kwds['ideal_class']
                del kwds['ideal_class']
            else:
                C = self._ideal_class_(len(gens))
            if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
                gens = gens[0]
            return C(self, gens, **kwds)

        def _ideal_class_(self, n=0):
            """
            Return the class that is used to implement ideals of this ring.

            NOTE:

            We copy the code from :class:`~sage.rings.ring.Ring`. This is
            necessary because not all rings inherit from that class, such
            as matrix algebras.

            INPUT:

            - ``n`` (optional integer, default 0): The number of generators
              of the ideal to be created.

            OUTPUT:

            The class that is used to implement ideals of this ring with
            ``n`` generators.

            NOTE:

            Often principal ideals (``n==1``) are implemented via a different
            class.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: MS._ideal_class_()
                <class 'sage.rings.noncommutative_ideals.Ideal_nc'>

            We don't know of a commutative ring in Sage that does not inherit
            from the base class of rings. So, we need to cheat in the next
            example::

                sage: super(Ring,QQ)._ideal_class_.__module__
                'sage.categories.rings'
                sage: super(Ring,QQ)._ideal_class_()
                <class 'sage.rings.ideal.Ideal_generic'>
                sage: super(Ring,QQ)._ideal_class_(1)
                <class 'sage.rings.ideal.Ideal_principal'>
                sage: super(Ring,QQ)._ideal_class_(2)
                <class 'sage.rings.ideal.Ideal_generic'>

            """
            from sage.rings.noncommutative_ideals import Ideal_nc
            try:
                if not self.is_commutative():
                    return Ideal_nc
            except (NotImplementedError, AttributeError):
                return Ideal_nc
            from sage.rings.ideal import Ideal_generic, Ideal_principal
            if n == 1:
                return Ideal_principal
            else:
                return Ideal_generic

        ##
        # Quotient rings
        # Again, this is defined in sage.rings.ring.pyx
        def quotient(self, I, names=None, **kwds):
            """
            Quotient of a ring by a two-sided ideal.

            INPUT:

            - ``I``: A twosided ideal of this ring.
            - ``names``: a list of strings to be used as names
              for the variables in the quotient ring.
            - further named arguments that may be passed to the
              quotient ring constructor.

            EXAMPLES:

            Usually, a ring inherits a method :meth:`sage.rings.ring.Ring.quotient`.
            So, we need a bit of effort to make the following example work with the
            category framework::

                sage: F.<x,y,z> = FreeAlgebra(QQ)
                sage: from sage.rings.noncommutative_ideals import Ideal_nc
                sage: from itertools import product
                sage: class PowerIdeal(Ideal_nc):
                ....:  def __init__(self, R, n):
                ....:      self._power = n
                ....:      Ideal_nc.__init__(self, R, [R.prod(m) for m in product(R.gens(), repeat=n)])
                ....:  def reduce(self, x):
                ....:      R = self.ring()
                ....:      return add([c*R(m) for m,c in x if len(m) < self._power], R(0))
                sage: I = PowerIdeal(F,3)
                sage: Q = Rings().parent_class.quotient(F, I); Q
                Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3)
                sage: Q.0
                xbar
                sage: Q.1
                ybar
                sage: Q.2
                zbar
                sage: Q.0*Q.1
                xbar*ybar
                sage: Q.0*Q.1*Q.0
                0
            """
            from sage.rings.quotient_ring import QuotientRing
            return QuotientRing(self, I, names=names, **kwds)

        def quo(self, I, names=None, **kwds):
            """
            Quotient of a ring by a two-sided ideal.

            NOTE:

            This is a synonym for :meth:`quotient`.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS

            ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`.

            However it is an instance of the parent class of the
            category of rings. The quotient method is inherited from
            there::

                sage: isinstance(MS,sage.rings.ring.Ring)
                False
                sage: isinstance(MS,Rings().parent_class)
                True
                sage: MS.quo(I,names = ['a','b','c','d'])
                Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0],
                <BLANKLINE>
                  [0 0]
                  [1 0],
                <BLANKLINE>
                  [0 0]
                  [0 1]
                )

            """
            return self.quotient(I, names=names, **kwds)

        def quotient_ring(self, I, names=None, **kwds):
            """
            Quotient of a ring by a two-sided ideal.

            NOTE:

            This is a synonyme for :meth:`quotient`.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS

            ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`,
            but it is an instance of the parent class of the category of
            rings. The quotient method is inherited from there::

                sage: isinstance(MS,sage.rings.ring.Ring)
                False
                sage: isinstance(MS,Rings().parent_class)
                True
                sage: MS.quotient_ring(I,names = ['a','b','c','d'])
                Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0],
                <BLANKLINE>
                  [0 0]
                  [1 0],
                <BLANKLINE>
                  [0 0]
                  [0 1]
                )

            """
            return self.quotient(I, names=names, **kwds)

        def __truediv__(self, I):
            """
            Since assigning generator names would not work properly,
            the construction of a quotient ring using division syntax
            is not supported.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS
                sage: MS/I
                Traceback (most recent call last):
                ...
                TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring.
            """
            raise TypeError(
                "Use self.quo(I) or self.quotient(I) to construct the quotient ring."
            )

        def __getitem__(self, arg):
            """
            Extend this ring by one or several elements to create a polynomial
            ring, a power series ring, or an algebraic extension.

            This is a convenience method intended primarily for interactive
            use.

            .. SEEALSO::

                :func:`~sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing`,
                :func:`~sage.rings.power_series_ring.PowerSeriesRing`,
                :meth:`~sage.rings.ring.Ring.extension`,
                :meth:`sage.rings.integer_ring.IntegerRing_class.__getitem__`,
                :meth:`sage.rings.matrix_space.MatrixSpace.__getitem__`,
                :meth:`sage.structure.parent.Parent.__getitem__`

            EXAMPLES:

            We create several polynomial rings::

                sage: ZZ['x']
                Univariate Polynomial Ring in x over Integer Ring
                sage: QQ['x']
                Univariate Polynomial Ring in x over Rational Field
                sage: GF(17)['abc']
                Univariate Polynomial Ring in abc over Finite Field of size 17
                sage: GF(17)['a,b,c']
                Multivariate Polynomial Ring in a, b, c over Finite Field of size 17
                sage: GF(17)['a']['b']
                Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17

            We can create Ore polynomial rings::

                sage: k.<t> = GF(5^3)
                sage: Frob = k.frobenius_endomorphism()
                sage: k['x', Frob]
                Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5

                sage: R.<t> = QQ[]
                sage: der = R.derivation()
                sage: R['d', der]
                Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt

            We can also create power series rings by using double brackets::

                sage: QQ[['t']]
                Power Series Ring in t over Rational Field
                sage: ZZ[['W']]
                Power Series Ring in W over Integer Ring

                sage: ZZ[['x,y,z']]
                Multivariate Power Series Ring in x, y, z over Integer Ring
                sage: ZZ[['x','T']]
                Multivariate Power Series Ring in x, T over Integer Ring

            Use :func:`~sage.rings.fraction_field.Frac` or
            :meth:`~sage.rings.ring.CommutativeRing.fraction_field` to obtain
            the fields of rational functions and Laurent series::

                sage: Frac(QQ['t'])
                Fraction Field of Univariate Polynomial Ring in t over Rational Field
                sage: Frac(QQ[['t']])
                Laurent Series Ring in t over Rational Field
                sage: QQ[['t']].fraction_field()
                Laurent Series Ring in t over Rational Field

            Note that the same syntax can be used to create number fields::

                sage: QQ[I]
                Number Field in I with defining polynomial x^2 + 1 with I = 1*I
                sage: QQ[I].coerce_embedding()
                Generic morphism:
                  From: Number Field in I with defining polynomial x^2 + 1 with I = 1*I
                  To:   Complex Lazy Field
                  Defn: I -> 1*I

            ::

                sage: QQ[sqrt(2)]
                Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
                sage: QQ[sqrt(2)].coerce_embedding()
                Generic morphism:
                  From: Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
                  To:   Real Lazy Field
                  Defn: sqrt2 -> 1.414213562373095?

            ::

                sage: QQ[sqrt(2),sqrt(3)]
                Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field

            and orders in number fields::

                sage: ZZ[I]
                Order in Number Field in I with defining polynomial x^2 + 1 with I = 1*I
                sage: ZZ[sqrt(5)]
                Order in Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?
                sage: ZZ[sqrt(2)+sqrt(3)]
                Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1 with a = 3.146264369941973?

            Embeddings are found for simple extensions (when that makes sense)::

                sage: QQi.<i> = QuadraticField(-1, 'i')
                sage: QQ[i].coerce_embedding()
                Generic morphism:
                  From: Number Field in i with defining polynomial x^2 + 1 with i = 1*I
                  To:   Complex Lazy Field
                  Defn: i -> 1*I

            TESTS:

            A few corner cases::

                sage: QQ[()]
                Multivariate Polynomial Ring in no variables over Rational Field

                sage: QQ[[]]
                Traceback (most recent call last):
                ...
                TypeError: power series rings must have at least one variable

            These kind of expressions do not work::

                sage: QQ['a,b','c']
                Traceback (most recent call last):
                ...
                ValueError: variable name 'a,b' is not alphanumeric
                sage: QQ[['a,b','c']]
                Traceback (most recent call last):
                ...
                ValueError: variable name 'a,b' is not alphanumeric

                sage: QQ[[['x']]]
                Traceback (most recent call last):
                ...
                TypeError: expected R[...] or R[[...]], not R[[[...]]]

            Extension towers are built as follows and use distinct generator names::

                sage: K = QQ[2^(1/3), 2^(1/2), 3^(1/3)]
                sage: K
                Number Field in a with defining polynomial x^3 - 2 over its base field
                sage: K.base_field()
                Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field
                sage: K.base_field().base_field()
                Number Field in b with defining polynomial x^3 - 3

            Embeddings::

                sage: QQ[I](I.pyobject())
                I
                sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1)
                sage: QQ[expr].coerce_embedding() is None
                False
                sage: QQ[sqrt(5)].gen() > 0
                True
                sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2)
                sage: QQ[expr].coerce_embedding()
                Generic morphism:
                  From: Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?
                  To:   Real Lazy Field
                  Defn: a -> 1.414213562373095?
            """
            def normalize_arg(arg):
                if isinstance(arg, (tuple, list)):
                    # Allowing arbitrary iterables would create confusion, but we
                    # may want to support a few more.
                    return tuple(arg)
                elif isinstance(arg, str):
                    return tuple(arg.split(','))
                else:
                    return (arg, )

            # 1. If arg is a list, try to return a power series ring.

            if isinstance(arg, list):
                if not arg:
                    raise TypeError(
                        "power series rings must have at least one variable")
                elif len(arg) == 1:
                    # R[["a,b"]], R[[(a,b)]]...
                    if isinstance(arg[0], list):
                        raise TypeError(
                            "expected R[...] or R[[...]], not R[[[...]]]")
                    elts = normalize_arg(arg[0])
                else:
                    elts = normalize_arg(arg)
                from sage.rings.power_series_ring import PowerSeriesRing
                return PowerSeriesRing(self, elts)

            if isinstance(arg, tuple):
                from sage.categories.morphism import Morphism
                from sage.rings.derivation import RingDerivation
                if len(arg) == 2 and isinstance(arg[1],
                                                (Morphism, RingDerivation)):
                    from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing
                    return OrePolynomialRing(self, arg[1], names=arg[0])

            # 2. Otherwise, if all specified elements are algebraic, try to
            #    return an algebraic extension

            elts = normalize_arg(arg)

            try:
                minpolys = [a.minpoly() for a in elts]
            except (AttributeError, NotImplementedError, ValueError,
                    TypeError):
                minpolys = None

            if minpolys:
                # how to pass in names?
                names = tuple(_gen_names(elts))
                if len(elts) == 1:
                    from sage.rings.all import CIF, CLF, RLF
                    elt = elts[0]
                    try:
                        iv = CIF(elt)
                    except (TypeError, ValueError):
                        emb = None
                    else:
                        # First try creating an ANRoot manually, because
                        # extension(..., embedding=CLF(expr)) (or
                        # ...QQbar(expr)) would normalize the expression in
                        # QQbar, which currently is VERY slow in many cases.
                        # This may fail when minpoly has close roots or elt is
                        # a complicated symbolic expression.
                        # TODO: Rewrite using #19362 and/or #17886 and/or
                        # #15600 once those issues are solved.
                        from sage.rings.qqbar import AlgebraicNumber, ANRoot
                        try:
                            elt = AlgebraicNumber(ANRoot(minpolys[0], iv))
                        except ValueError:
                            pass
                        # Force a real embedding when possible, to get the
                        # right ordered ring structure.
                        if (iv.imag().is_zero() or iv.imag().contains_zero()
                                and elt.imag().is_zero()):
                            emb = RLF(elt)
                        else:
                            emb = CLF(elt)
                        return self.extension(minpolys[0],
                                              names[0],
                                              embedding=emb)
                try:
                    # Doing the extension all at once is best, if possible...
                    return self.extension(minpolys, names)
                except (TypeError, ValueError):
                    # ...but we can also construct it iteratively
                    return reduce(lambda R, ext: R.extension(*ext),
                                  zip(minpolys, names), self)

            # 2. Otherwise, try to return a polynomial ring

            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            return PolynomialRing(self, elts)

        def free_module(self, base=None, basis=None, map=True):
            """
            Return a free module `V` over the specified subring together with maps to and from `V`.

            The default implementation only supports the case that the base ring is the ring itself.

            INPUT:

            - ``base`` -- a subring `R` so that this ring is isomorphic
              to a finite-rank free `R`-module `V`

            - ``basis`` -- (optional) a basis for this ring over the base

            - ``map`` -- boolean (default ``True``), whether to return
              `R`-linear maps to and from `V`

            OUTPUT:

            - A finite-rank free `R`-module `V`

            - An `R`-module isomorphism from `V` to this ring
              (only included if ``map`` is ``True``)

            - An `R`-module isomorphism from this ring to `V`
              (only included if ``map`` is ``True``)

            EXAMPLES::

                sage: R.<x> = QQ[[]]
                sage: V, from_V, to_V = R.free_module(R)
                sage: v = to_V(1+x); v
                (1 + x)
                sage: from_V(v)
                1 + x
                sage: W, from_W, to_W = R.free_module(R, basis=(1-x))
                sage: W is V
                True
                sage: w = to_W(1+x); w
                (1 - x^2)
                sage: from_W(w)
                1 + x + O(x^20)
            """
            if base is None:
                base = self.base_ring()
            if base is self:
                V = self**1
                if not map:
                    return V
                if basis is not None:
                    if isinstance(basis, (list, tuple)):
                        if len(basis) != 1:
                            raise ValueError("Basis must have length 1")
                        basis = basis[0]
                    basis = self(basis)
                    if not basis.is_unit():
                        raise ValueError("Basis element must be a unit")
                from sage.modules.free_module_morphism import BaseIsomorphism1D_from_FM, BaseIsomorphism1D_to_FM
                Hfrom = V.Hom(self)
                Hto = self.Hom(V)
                from_V = Hfrom.__make_element_class__(
                    BaseIsomorphism1D_from_FM)(Hfrom, basis=basis)
                to_V = Hto.__make_element_class__(BaseIsomorphism1D_to_FM)(
                    Hto, basis=basis)
                return V, from_V, to_V
            else:
                if not self.has_coerce_map_from(base):
                    raise ValueError("base must be a subring of this ring")
                raise NotImplementedError

    class ElementMethods:
        def is_unit(self):
            r"""
            Return whether this element is a unit in the ring.

            .. NOTE::

                This is a generic implementation for (non-commutative) rings
                which only works for the one element, its additive inverse, and
                the zero element.  Most rings should provide a more specialized
                implementation.

            EXAMPLES::

                sage: MS = MatrixSpace(ZZ, 2)
                sage: MS.one().is_unit()
                True
                sage: MS.zero().is_unit()
                False
                sage: MS([1,2,3,4]).is_unit()
                False
            """
            if self.is_one() or (-self).is_one():
                return True
            if self.is_zero():  # now 0 != 1
                return False
            raise NotImplementedError

        def inverse_of_unit(self):
            r"""
            Return the inverse of this element if it is a unit.

            OUTPUT:

            An element in the same ring as this element.

            EXAMPLES::

                sage: R.<x> = ZZ[]
                sage: S = R.quo(x^2 + x + 1)
                sage: S(1).inverse_of_unit()
                1

            This method fails when the element is not a unit::

                sage: 2.inverse_of_unit()
                Traceback (most recent call last):
                ...
                ArithmeticError: inverse does not exist

            The inverse returned is in the same ring as this element::

                sage: a = -1
                sage: a.parent()
                Integer Ring
                sage: a.inverse_of_unit().parent()
                Integer Ring

            Note that this is often not the case when computing inverses in other ways::

                sage: (~a).parent()
                Rational Field
                sage: (1/a).parent()
                Rational Field

            """
            try:
                if not self.is_unit():
                    raise ArithmeticError("element is not a unit")
            except NotImplementedError:
                # if an element does not implement is_unit, we just try to
                # invert it anyway; if the result is in the ring again, it was
                # a unit
                pass

            inverse = ~self
            if inverse not in self.parent():
                raise ArithmeticError("element is not a unit")

            # return the inverse (with the correct parent)
            return self.parent()(inverse)

        def _divide_if_possible(self, y):
            """
            Divide ``self`` by ``y`` if possible and raise a
            ``ValueError`` otherwise.

            EXAMPLES::

                sage: 4._divide_if_possible(2)
                2
                sage: _.parent()
                Integer Ring

            ::

                sage: 4._divide_if_possible(3)
                Traceback (most recent call last):
                ...
                ValueError: 4 is not divisible by 3
            """
            q, r = self.quo_rem(y)
            if r != 0:
                raise ValueError("%s is not divisible by %s" % (self, y))
            return q
Ejemplo n.º 8
0
class Rings(CategoryWithAxiom):
    """
    The category of rings

    Associative rings with unit, not necessarily commutative

    EXAMPLES::

        sage: Rings()
        Category of rings
        sage: sorted(Rings().super_categories(), key=str)
        [Category of rngs, Category of semirings]

        sage: sorted(Rings().axioms())
        ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveInverse',
         'AdditiveUnital', 'Associative', 'Distributive', 'Unital']

        sage: Rings() is (CommutativeAdditiveGroups() & Monoids()).Distributive()
        True
        sage: Rings() is Rngs().Unital()
        True
        sage: Rings() is Semirings().AdditiveInverse()
        True

    TESTS::

        sage: TestSuite(Rings()).run()

    .. TODO::

        (see: http://trac.sagemath.org/sage_trac/wiki/CategoriesRoadMap)

        - Make Rings() into a subcategory or alias of Algebras(ZZ);

        - A parent P in the category ``Rings()`` should automatically be
          in the category ``Algebras(P)``.
    """

    _base_category_class_and_axiom = (Rngs, "Unital")

    class SubcategoryMethods:
        def NoZeroDivisors(self):
            """
            Return the full subcategory of the objects of ``self`` having
            no nonzero zero divisors.

            A *zero divisor* in a ring `R` is an element `x \in R` such
            that there exists a nonzero element `y \in R` such that
            `x \cdot y = 0` or `y \cdot x = 0`
            (see :wikipedia:`Zero_divisor`).

            EXAMPLES::

                sage: Rings().NoZeroDivisors()
                Category of domains

            .. NOTE::

                This could be generalized to
                :class:`MagmasAndAdditiveMagmas.Distributive.AdditiveUnital`.

            TESTS::

                sage: TestSuite(Rings().NoZeroDivisors()).run()
                sage: Algebras(QQ).NoZeroDivisors.__module__
                'sage.categories.rings'
            """
            return self._with_axiom('NoZeroDivisors')

        def Division(self):
            """
            Return the full subcategory of the division objects of ``self``.

            A ring satisfies the *division axiom* if all non-zero
            elements have multiplicative inverses.

            .. NOTE::

                This could be generalized to
                :class:`MagmasAndAdditiveMagmas.Distributive.AdditiveUnital`.

            EXAMPLES::

                sage: Rings().Division()
                Category of division rings
                sage: Rings().Commutative().Division()
                Category of fields

            TESTS::

                sage: TestSuite(Rings().Division()).run()
                sage: Algebras(QQ).Division.__module__
                'sage.categories.rings'
            """
            return self._with_axiom('Division')

    NoZeroDivisors = LazyImport('sage.categories.domains',
                                'Domains',
                                at_startup=True)
    Division = LazyImport('sage.categories.division_rings',
                          'DivisionRings',
                          at_startup=True)
    Commutative = LazyImport('sage.categories.commutative_rings',
                             'CommutativeRings',
                             at_startup=True)

    class ParentMethods:
        def is_ring(self):
            """
            Return True, since this in an object of the category of rings.

            EXAMPLES::

                sage: Parent(QQ,category=Rings()).is_ring()
                True

            """
            return True

        def is_zero(self):
            """
            Return ``True`` if this is the zero ring.

            EXAMPLES::

                sage: Integers(1).is_zero()
                True
                sage: Integers(2).is_zero()
                False
                sage: QQ.is_zero()
                False
                sage: R.<x> = ZZ[]
                sage: R.quo(1).is_zero()
                True
                sage: R.<x> = GF(101)[]
                sage: R.quo(77).is_zero()
                True
                sage: R.quo(x^2+1).is_zero()
                False
            """
            return self.one() == self.zero()

        def bracket(self, x, y):
            """
            Returns the Lie bracket `[x, y] = x y - y x` of `x` and `y`.

            INPUT:

             - ``x``, ``y`` -- elements of ``self``

            EXAMPLES::

                sage: F = AlgebrasWithBasis(QQ).example()
                sage: F
                An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                sage: a,b,c = F.algebra_generators()
                sage: F.bracket(a,b)
                B[word: ab] - B[word: ba]

            This measures the default of commutation between `x` and `y`.
            `F` endowed with the bracket operation is a Lie algebra;
            in particular, it satisfies Jacobi's identity::

                sage: F.bracket( F.bracket(a,b), c) + F.bracket(F.bracket(b,c),a) + F.bracket(F.bracket(c,a),b)
                0
            """
            return x * y - y * x

        def _Hom_(self, Y, category):
            r"""
            Returns the homset from ``self`` to ``Y`` in the category ``category``

            INPUT:

            - ``Y`` -- a ring
            - ``category`` -- a subcategory of :class:`Rings`() or None

            The sole purpose of this method is to construct the homset
            as a :class:`~sage.rings.homset.RingHomset`. If
            ``category`` is specified and is not a subcategory of
            :class:`Rings`, a ``TypeError`` is raised instead

            This method is not meant to be called directly. Please use
            :func:`sage.categories.homset.Hom` instead.

            EXAMPLES::

                sage: H = QQ._Hom_(QQ, category = Rings()); H
                Set of Homomorphisms from Rational Field to Rational Field
                sage: H.__class__
                <class 'sage.rings.homset.RingHomset_generic_with_category'>

            TESTS::

                sage: Hom(QQ, QQ, category = Rings()).__class__
                <class 'sage.rings.homset.RingHomset_generic_with_category'>

                sage: Hom(CyclotomicField(3), QQ, category = Rings()).__class__
                <class 'sage.rings.number_field.morphism.CyclotomicFieldHomset_with_category'>

                sage: TestSuite(Hom(QQ, QQ, category = Rings())).run() # indirect doctest

            """
            if category is not None and not category.is_subcategory(Rings()):
                raise TypeError("%s is not a subcategory of Rings()" %
                                category)
            if Y not in Rings():
                raise TypeError("%s is not a ring" % Y)
            from sage.rings.homset import RingHomset
            return RingHomset(self, Y, category=category)

        # this is already in sage.rings.ring.Ring,
        # but not all rings descend from that class,
        # e.g., matrix spaces.
        def _mul_(self, x, switch_sides=False):
            """
            Multiplication of rings with, e.g., lists.

            NOTE:

            This method is used to create ideals. It is
            the same as the multiplication method for
            :class:`~sage.rings.ring.Ring`. However, not
            all parents that belong to the category of
            rings also inherits from the base class of
            rings. Therefore, we implemented a ``__mul__``
            method for parents, that calls a ``_mul_``
            method implemented here. See :trac:`7797`.

            INPUT:

            - `x`, an object to multiply with.
            - `switch_sides` (optional bool): If ``False``,
              the product is ``self*x``; if ``True``, the
              product is ``x*self``.

            EXAMPLE:

            As we mentioned above, this method is called
            when a ring is involved that does not inherit
            from the base class of rings. This is the case,
            e.g., for matrix algebras::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS*2     # indirect doctest
                Left Ideal
                (
                  [2 0]
                  [0 2]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            In the next example, the ring and the other factor switch sides
            in the product::

                sage: [MS.2]*MS
                Right Ideal
                (
                  [0 0]
                  [1 0]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            AUTHOR:

            - Simon King (2011-03-22)

            """
            try:
                if self.is_commutative():
                    return self.ideal(x)
            except (AttributeError, NotImplementedError):
                pass
            try:
                side = x.side()
            except AttributeError:
                return self.ideal(x, side='right' if switch_sides else 'left')
            # presumably x is an ideal...
            try:
                x = x.gens()
            except (AttributeError, NotImplementedError):
                pass  # ... not an ideal
            if switch_sides:
                if side in ['right', 'twosided']:
                    return self.ideal(x, side=side)
                elif side == 'left':
                    return self.ideal(x, side='twosided')
            else:
                if side in ['left', 'twosided']:
                    return self.ideal(x, side=side)
                elif side == 'right':
                    return self.ideal(x, side='twosided')
            # duck typing failed
            raise TypeError(
                "Don't know how to transform %s into an ideal of %s" %
                (x, self))

        @cached_method
        def ideal_monoid(self):
            """
            The monoid of the ideals of this ring.

            NOTE:

            The code is copied from the base class of rings.
            This is since there are rings that do not inherit
            from that class, such as matrix algebras.  See
            :trac:`7797`.

            EXAMPLE::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS.ideal_monoid()
                Monoid of ideals of Full MatrixSpace of 2 by 2 dense matrices
                over Rational Field

            Note that the monoid is cached::

                sage: MS.ideal_monoid() is MS.ideal_monoid()
                True

            """
            try:
                from sage.rings.ideal_monoid import IdealMonoid
                return IdealMonoid(self)
            except TypeError:
                from sage.rings.noncommutative_ideals import IdealMonoid_nc
                return IdealMonoid_nc(self)

        def characteristic(self):
            """
            Return the characteristic of this ring.

            EXAMPLES::

                sage: QQ.characteristic()
                0
                sage: GF(19).characteristic()
                19
                sage: Integers(8).characteristic()
                8
                sage: Zp(5).characteristic()
                0
            """
            from sage.rings.infinity import infinity
            from sage.rings.integer_ring import ZZ
            order_1 = self.one().additive_order()
            return ZZ.zero() if order_1 is infinity else order_1

        def _test_characteristic(self, **options):
            """
            Run generic tests on the method :meth:`characteristic`.

            See also: :class:`TestSuite`.

            EXAMPLES::

                sage: ZZ._test_characteristic()
            """
            tester = self._tester(**options)
            try:
                characteristic = self.characteristic()
            except AttributeError:
                return  # raised when self.one() does not have a additive_order()
            except NotImplementedError:
                return

            # test that #12988 is fixed
            from sage.rings.integer import Integer
            tester.assertIsInstance(characteristic, Integer)

        def ideal(self, *args, **kwds):
            """
            Create an ideal of this ring.

            NOTE:

            The code is copied from the base class
            :class:`~sage.rings.ring.Ring`. This is
            because there are rings that do not inherit
            from that class, such as matrix algebras.
            See :trac:`7797`.

            INPUT:

            - An element or a list/tuple/sequence of elements.
            - ``coerce`` (optional bool, default ``True``):
              First coerce the elements into this ring.
            - ``side``, optional string, one of ``"twosided"``
              (default), ``"left"``, ``"right"``: determines
              whether the resulting ideal is twosided, a left
              ideal or a right ideal.

            EXAMPLE::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: isinstance(MS,Ring)
                False
                sage: MS in Rings()
                True
                sage: MS.ideal(2)
                Twosided Ideal
                (
                  [2 0]
                  [0 2]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
                sage: MS.ideal([MS.0,MS.1],side='right')
                Right Ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0]
                )
                 of Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            """
            if 'coerce' in kwds:
                coerce = kwds['coerce']
                del kwds['coerce']
            else:
                coerce = True

            from sage.rings.ideal import Ideal_generic
            from types import GeneratorType
            if len(args) == 0:
                gens = [self(0)]
            else:
                gens = args
                while isinstance(
                        gens, (list, tuple, GeneratorType)) and len(gens) == 1:
                    first = gens[0]
                    if isinstance(first, Ideal_generic):
                        R = first.ring()
                        m = self.convert_map_from(R)
                        if m is not None:
                            gens = [m(g) for g in first.gens()]
                            coerce = False
                        else:
                            m = R.convert_map_from(self)
                            if m is not None:
                                raise NotImplementedError
                            else:
                                raise TypeError
                        break
                    elif isinstance(first, (list, tuple, GeneratorType)):
                        gens = first
                    else:
                        try:
                            if self.has_coerce_map_from(first):
                                gens = first.gens(
                                )  # we have a ring as argument
                            elif isinstance(first, Element):
                                gens = [first]
                            else:
                                raise ArithmeticError(
                                    "There is no coercion from %s to %s" %
                                    (first, self))
                        except TypeError:  # first may be a ring element
                            pass
                        break
            if coerce:
                gens = [self(g) for g in gens]
            from sage.categories.principal_ideal_domains import PrincipalIdealDomains
            if self in PrincipalIdealDomains():
                # Use GCD algorithm to obtain a principal ideal
                g = gens[0]
                if len(gens) == 1:
                    try:
                        g = g.gcd(
                            g
                        )  # note: we set g = gcd(g, g) to "canonicalize" the generator: make polynomials monic, etc.
                    except (AttributeError, NotImplementedError):
                        pass
                else:
                    for h in gens[1:]:
                        g = g.gcd(h)
                gens = [g]
            if 'ideal_class' in kwds:
                C = kwds['ideal_class']
                del kwds['ideal_class']
            else:
                C = self._ideal_class_(len(gens))
            if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
                gens = gens[0]
            return C(self, gens, **kwds)

        def _ideal_class_(self, n=0):
            """
            Return the class that is used to implement ideals of this ring.

            NOTE:

            We copy the code from :class:`~sage.rings.ring.Ring`. This is
            necessary because not all rings inherit from that class, such
            as matrix algebras.

            INPUT:

            - ``n`` (optional integer, default 0): The number of generators
              of the ideal to be created.

            OUTPUT:

            The class that is used to implement ideals of this ring with
            ``n`` generators.

            NOTE:

            Often principal ideals (``n==1``) are implemented via a different
            class.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ,2,2)
                sage: MS._ideal_class_()
                <class 'sage.rings.noncommutative_ideals.Ideal_nc'>

            We don't know of a commutative ring in Sage that does not inherit
            from the base class of rings. So, we need to cheat in the next
            example::

                sage: super(Ring,QQ)._ideal_class_.__module__
                'sage.categories.rings'
                sage: super(Ring,QQ)._ideal_class_()
                <class 'sage.rings.ideal.Ideal_generic'>
                sage: super(Ring,QQ)._ideal_class_(1)
                <class 'sage.rings.ideal.Ideal_principal'>
                sage: super(Ring,QQ)._ideal_class_(2)
                <class 'sage.rings.ideal.Ideal_generic'>

            """
            from sage.rings.noncommutative_ideals import Ideal_nc
            try:
                if not self.is_commutative():
                    return Ideal_nc
            except (NotImplementedError, AttributeError):
                return Ideal_nc
            from sage.rings.ideal import Ideal_generic, Ideal_principal
            if n == 1:
                return Ideal_principal
            else:
                return Ideal_generic

        ##
        # Quotient rings
        # Again, this is defined in sage.rings.ring.pyx
        def quotient(self, I, names=None):
            """
            Quotient of a ring by a two-sided ideal.

            INPUT:

            - ``I``: A twosided ideal of this ring.
            - ``names``: a list of strings to be used as names
              for the variables in the quotient ring.

            EXAMPLES:

            Usually, a ring inherits a method :meth:`sage.rings.ring.Ring.quotient`.
            So, we need a bit of effort to make the following example work with the
            category framework::

                sage: F.<x,y,z> = FreeAlgebra(QQ)
                sage: from sage.rings.noncommutative_ideals import Ideal_nc
                sage: from itertools import product
                sage: class PowerIdeal(Ideal_nc):
                ....:  def __init__(self, R, n):
                ....:      self._power = n
                ....:      Ideal_nc.__init__(self, R, [R.prod(m) for m in product(R.gens(), repeat=n)])
                ....:  def reduce(self, x):
                ....:      R = self.ring()
                ....:      return add([c*R(m) for m,c in x if len(m) < self._power], R(0))
                ....:
                sage: I = PowerIdeal(F,3)
                sage: Q = Rings().parent_class.quotient(F, I); Q
                Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3)
                sage: Q.0
                xbar
                sage: Q.1
                ybar
                sage: Q.2
                zbar
                sage: Q.0*Q.1
                xbar*ybar
                sage: Q.0*Q.1*Q.0
                0
            """
            from sage.rings.quotient_ring import QuotientRing
            return QuotientRing(self, I, names=names)

        def quo(self, I, names=None):
            """
            Quotient of a ring by a two-sided ideal.

            NOTE:

            This is a synonym for :meth:`quotient`.

            EXAMPLE::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS

            ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`.

            However it is an instance of the parent class of the
            category of rings. The quotient method is inherited from
            there::

                sage: isinstance(MS,sage.rings.ring.Ring)
                False
                sage: isinstance(MS,Rings().parent_class)
                True
                sage: MS.quo(I,names = ['a','b','c','d'])
                Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0],
                <BLANKLINE>
                  [0 0]
                  [1 0],
                <BLANKLINE>
                  [0 0]
                  [0 1]
                )

            """
            return self.quotient(I, names=names)

        def quotient_ring(self, I, names=None):
            """
            Quotient of a ring by a two-sided ideal.

            NOTE:

            This is a synonyme for :meth:`quotient`.

            EXAMPLE::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS

            ``MS`` is not an instance of :class:`~sage.rings.ring.Ring`,
            but it is an instance of the parent class of the category of
            rings. The quotient method is inherited from there::

                sage: isinstance(MS,sage.rings.ring.Ring)
                False
                sage: isinstance(MS,Rings().parent_class)
                True
                sage: MS.quotient_ring(I,names = ['a','b','c','d'])
                Quotient of Full MatrixSpace of 2 by 2 dense matrices over Rational Field by the ideal
                (
                  [1 0]
                  [0 0],
                <BLANKLINE>
                  [0 1]
                  [0 0],
                <BLANKLINE>
                  [0 0]
                  [1 0],
                <BLANKLINE>
                  [0 0]
                  [0 1]
                )

            """
            return self.quotient(I, names=names)

        def __truediv__(self, I):
            """
            Since assigning generator names would not work properly,
            the construction of a quotient ring using division syntax
            is not supported.

            EXAMPLE::

                sage: MS = MatrixSpace(QQ,2)
                sage: I = MS*MS.gens()*MS
                sage: MS/I
                Traceback (most recent call last):
                ...
                TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring.
            """
            raise TypeError(
                "Use self.quo(I) or self.quotient(I) to construct the quotient ring."
            )

        def __getitem__(self, arg):
            """
            Extend this ring by one or several elements to create a polynomial
            ring, a power series ring, or an algebraic extension.

            This is a convenience method intended primarily for interactive
            use.

            .. SEEALSO::

                :func:`~sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing`,
                :func:`~sage.rings.power_series_ring.PowerSeriesRing`,
                :meth:`~sage.rings.ring.Ring.extension`,
                :meth:`sage.rings.integer_ring.IntegerRing_class.__getitem__`,
                :meth:`sage.rings.matrix_space.MatrixSpace.__getitem__`,
                :meth:`sage.structure.parent.Parent.__getitem__`

            EXAMPLES:

            We create several polynomial rings::

                sage: ZZ['x']
                Univariate Polynomial Ring in x over Integer Ring
                sage: QQ['x']
                Univariate Polynomial Ring in x over Rational Field
                sage: GF(17)['abc']
                Univariate Polynomial Ring in abc over Finite Field of size 17
                sage: GF(17)['a,b,c']
                Multivariate Polynomial Ring in a, b, c over Finite Field of size 17
                sage: GF(17)['a']['b']
                Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17

            We can also create power series rings by using double brackets::

                sage: QQ[['t']]
                Power Series Ring in t over Rational Field
                sage: ZZ[['W']]
                Power Series Ring in W over Integer Ring

                sage: ZZ[['x,y,z']]
                Multivariate Power Series Ring in x, y, z over Integer Ring
                sage: ZZ[['x','T']]
                Multivariate Power Series Ring in x, T over Integer Ring

            Use :func:`~sage.rings.fraction_field.Frac` or
            :meth:`~sage.rings.ring.CommutativeRing.fraction_field` to obtain
            the fields of rational functions and Laurent series::

                sage: Frac(QQ['t'])
                Fraction Field of Univariate Polynomial Ring in t over Rational Field
                sage: Frac(QQ[['t']])
                Laurent Series Ring in t over Rational Field
                sage: QQ[['t']].fraction_field()
                Laurent Series Ring in t over Rational Field

            Note that the same syntax can be used to create number fields::

                sage: QQ[I]
                Number Field in I with defining polynomial x^2 + 1
                sage: QQ[sqrt(2)]
                Number Field in sqrt2 with defining polynomial x^2 - 2
                sage: QQ[sqrt(2),sqrt(3)]
                Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field

            and orders in number fields::

                sage: ZZ[I]
                Order in Number Field in I with defining polynomial x^2 + 1
                sage: ZZ[sqrt(5)]
                Order in Number Field in sqrt5 with defining polynomial x^2 - 5
                sage: ZZ[sqrt(2)+sqrt(3)]
                Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1

            TESTS:

            A few corner cases::

                sage: QQ[()]
                Multivariate Polynomial Ring in no variables over Rational Field

                sage: QQ[[]]
                Traceback (most recent call last):
                ...
                TypeError: power series rings must have at least one variable

            Some flexibility is allowed when specifying variables::

                sage: QQ["x", SR.var('y'), polygen(CC, 'z')]
                Multivariate Polynomial Ring in x, y, z over Rational Field
                sage: QQ[["x", SR.var('y'), polygen(CC, 'z')]]
                Multivariate Power Series Ring in x, y, z over Rational Field

            but more baroque expressions do not work::

                sage: QQ['a,b','c']
                Traceback (most recent call last):
                ...
                ValueError: variable name 'a,b' is not alphanumeric
                sage: QQ[['a,b','c']]
                Traceback (most recent call last):
                ...
                ValueError: variable name 'a,b' is not alphanumeric

                sage: QQ[[['x']]]
                Traceback (most recent call last):
                ...
                TypeError: expected R[...] or R[[...]], not R[[[...]]]

            Extension towers are built as follows and use distinct generator names::

                sage: K = QQ[2^(1/3), 2^(1/2), 3^(1/3)]
                sage: K
                Number Field in a with defining polynomial x^3 - 2 over its base field
                sage: K.base_field()
                Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field
                sage: K.base_field().base_field()
                Number Field in b with defining polynomial x^3 - 3

            """
            def normalize_arg(arg):
                if isinstance(arg, (tuple, list)):
                    # Allowing arbitrary iterables would create confusion, but we
                    # may want to support a few more.
                    return tuple(arg)
                elif isinstance(arg, str):
                    return tuple(arg.split(','))
                else:
                    return (arg, )

            # 1. If arg is a list, try to return a power series ring.

            if isinstance(arg, list):
                if arg == []:
                    raise TypeError(
                        "power series rings must have at least one variable")
                elif len(arg) == 1:
                    # R[["a,b"]], R[[(a,b)]]...
                    if isinstance(arg[0], list):
                        raise TypeError(
                            "expected R[...] or R[[...]], not R[[[...]]]")
                    elts = normalize_arg(arg[0])
                else:
                    elts = normalize_arg(arg)
                from sage.rings.power_series_ring import PowerSeriesRing
                return PowerSeriesRing(self, elts)

            # 2. Otherwise, if all specified elements are algebraic, try to
            #    return an algebraic extension

            elts = normalize_arg(arg)

            try:
                minpolys = [a.minpoly() for a in elts]
            except (AttributeError, NotImplementedError, ValueError,
                    TypeError):
                minpolys = None

            if minpolys:
                # how to pass in names?
                # TODO: set up embeddings
                names = tuple(_gen_names(elts))
                try:
                    # Doing the extension all at once is best, if possible...
                    return self.extension(minpolys, names)
                except (TypeError, ValueError):
                    # ...but we can also construct it iteratively
                    return reduce(lambda R, ext: R.extension(*ext),
                                  zip(minpolys, names), self)

            # 2. Otherwise, try to return a polynomial ring

            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            return PolynomialRing(self, elts)

    class ElementMethods:
        def is_unit(self):
            r"""
            Return whether this element is a unit in the ring.

            .. NOTE::

                This is a generic implementation for (non-commutative) rings
                which only works for the one element, its additive inverse, and
                the zero element.  Most rings should provide a more specialized
                implementation.

            EXAMPLES::

                sage: MS = MatrixSpace(ZZ, 2)
                sage: MS.one().is_unit()
                True
                sage: MS.zero().is_unit()
                False
                sage: MS([1,2,3,4]).is_unit()
                False
            """
            if self.is_one() or (-self).is_one():
                return True
            if self.is_zero():  # now 0 != 1
                return False
            raise NotImplementedError
Ejemplo n.º 9
0
class CoalgebrasWithBasis(CategoryWithAxiom_over_base_ring):
    """
    The category of coalgebras with a distinguished basis.

    EXAMPLES::

        sage: CoalgebrasWithBasis(ZZ)
        Category of coalgebras with basis over Integer Ring
        sage: sorted(CoalgebrasWithBasis(ZZ).super_categories(), key=str)
        [Category of coalgebras over Integer Ring,
         Category of modules with basis over Integer Ring]

    TESTS::

        sage: TestSuite(CoalgebrasWithBasis(ZZ)).run()
    """
    Graded = LazyImport('sage.categories.graded_coalgebras_with_basis',
                        'GradedCoalgebrasWithBasis')

    class Filtered(FilteredModulesCategory):
        """
        Category of filtered coalgebras.
        """

    class ParentMethods:

        @abstract_method(optional = True)
        def coproduct_on_basis(self, i):
            """
            The coproduct of the algebra on the basis (optional).

            INPUT:

            - ``i`` -- the indices of an element of the basis of ``self``

            Returns the coproduct of the corresponding basis elements
            If implemented, the coproduct of the algebra is defined
            from it by linearity.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: (a, b) = A._group.gens()
                sage: A.coproduct_on_basis(a)
                B[(1,2,3)] # B[(1,2,3)]
            """

        @lazy_attribute
        def coproduct(self):
            r"""
            If :meth:`coproduct_on_basis` is available, construct the
            coproduct morphism from ``self`` to ``self`` `\otimes`
            ``self`` by extending it by linearity. Otherwise, use
            :meth:`~Coalgebras.Realizations.ParentMethods.coproduct_by_coercion`,
            if available.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, A.coproduct(a)
                (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)])
                sage: b, A.coproduct(b)
                (B[(1,3)], B[(1,3)] # B[(1,3)])

            """
            if self.coproduct_on_basis is not NotImplemented:
                # TODO: if self is a hopf algebra, then one would want
                # to create a morphism of algebras with basis instead
                # should there be a method self.coproduct_homset_category?
                return Hom(self, tensor([self, self]), ModulesWithBasis(self.base_ring()))(on_basis = self.coproduct_on_basis)
            elif hasattr(self, "coproduct_by_coercion"):
                return self.coproduct_by_coercion

        @abstract_method(optional = True)
        def counit_on_basis(self, i):
            """
            The counit of the algebra on the basis (optional).

            INPUT:

            - ``i`` -- the indices of an element of the basis of ``self``

            Returns the counit of the corresponding basis elements
            If implemented, the counit of the algebra is defined
            from it by linearity.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: (a, b) = A._group.gens()
                sage: A.counit_on_basis(a)
                1
            """

        @lazy_attribute
        def counit(self):
            r"""
            If :meth:`counit_on_basis` is available, construct the
            counit morphism from ``self`` to ``self`` `\otimes`
            ``self`` by extending it by linearity

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, A.counit(a)
                (B[(1,2,3)], 1)
                sage: b, A.counit(b)
                (B[(1,3)], 1)

            """
            if self.counit_on_basis is not NotImplemented:
                return self.module_morphism(self.counit_on_basis,codomain=self.base_ring())
            elif hasattr(self, "counit_by_coercion"):
                return self.counit_by_coercion

    class ElementMethods:
        def coproduct_iterated(self, n=1):
            r"""
            Apply ``n`` coproducts to ``self``.

            .. TODO::

                Remove dependency on ``modules_with_basis`` methods.

            EXAMPLES::

                sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi()
                sage: Psi[2,2].coproduct_iterated(0)
                Psi[2, 2]
                sage: Psi[2,2].coproduct_iterated(2)
                Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2]
                 + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2]
                 + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[]

            TESTS::

                sage: p = SymmetricFunctions(QQ).p()
                sage: p[5,2,2].coproduct_iterated()
                p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5]
                 + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[]
                sage: p([]).coproduct_iterated(3)
                p[] # p[] # p[] # p[]

            ::

                sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi()
                sage: Psi[2,2].coproduct_iterated(0)
                Psi[2, 2]
                sage: Psi[2,2].coproduct_iterated(3)
                Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2]
                 + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2]
                 + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[]
                 + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[]
                 + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[]

            ::

                sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m()
                sage: m[[1,3],[2]].coproduct_iterated(2)
                m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}}
                 + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{}
                 + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{}
                 + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{}
                 + m{{1, 3}, {2}} # m{} # m{}
                sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0)
                (m{} # m{} # m{} # m{}, m{{1, 3}, {2}})
            """
            if n < 0:
                raise ValueError("cannot take fewer than 0 coproduct iterations: %s < 0" % str(n))
            if n == 0:
                return self
            if n == 1:
                return self.coproduct()
            from sage.functions.all import floor, ceil
            from sage.rings.integer import Integer

            # Use coassociativity of `\Delta` to perform many coproducts simultaneously.
            fn = floor(Integer(n-1)/2); cn = ceil(Integer(n-1)/2)
            split = lambda a,b: tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)])
            return self.coproduct().apply_multilinear_morphism(split)

    class Super(SuperModulesCategory):
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: C = Coalgebras(ZZ).WithBasis().Super()
                sage: sorted(C.super_categories(), key=str)  # indirect doctest
                [Category of graded coalgebras with basis over Integer Ring,
                 Category of super coalgebras over Integer Ring,
                 Category of super modules with basis over Integer Ring]
            """
            return [self.base_category().Graded()]
Ejemplo n.º 10
0
    class FiniteDimensional(CategoryWithAxiom_over_base_ring):

        WithBasis = LazyImport('sage.categories.finite_dimensional_semisimple_algebras_with_basis', 'FiniteDimensionalSemisimpleAlgebrasWithBasis')
Ejemplo n.º 11
0
class Semigroups(CategoryWithAxiom):
    """
    The category of (multiplicative) semigroups.

    A *semigroup* is an associative :class:`magma <Magmas>`, that is a
    set endowed with a multiplicative binary operation `*` which is
    associative (see :wikipedia:`Semigroup`).

    The operation `*` is not required to have a neutral element. A
    semigroup for which such an element exists is a :class:`monoid
    <sage.categories.monoids.Monoids>`.

    EXAMPLES::

        sage: C = Semigroups(); C
        Category of semigroups
        sage: C.super_categories()
        [Category of magmas]
        sage: C.all_super_categories()
        [Category of semigroups, Category of magmas,
         Category of sets, Category of sets with partial maps, Category of objects]
        sage: C.axioms()
        frozenset(['Associative'])
        sage: C.example()
        An example of a semigroup: the left zero semigroup

    TESTS::

        sage: TestSuite(C).run()
    """
    _base_category_class_and_axiom = (Magmas, "Associative")

    def example(self, choice="leftzero", **kwds):
        r"""
        Returns an example of a semigroup, as per
        :meth:`Category.example()
        <sage.categories.category.Category.example>`.

        INPUT:

        - ``choice`` -- str (default: 'leftzero'). Can be either 'leftzero'
          for the left zero semigroup, or 'free' for the free semigroup.
        - ``**kwds`` -- keyword arguments passed onto the constructor for the
          chosen semigroup.

        EXAMPLES::

            sage: Semigroups().example(choice='leftzero')
            An example of a semigroup: the left zero semigroup
            sage: Semigroups().example(choice='free')
            An example of a semigroup: the free semigroup generated by ('a', 'b', 'c', 'd')
            sage: Semigroups().example(choice='free', alphabet=('a','b'))
            An example of a semigroup: the free semigroup generated by ('a', 'b')

        """
        import sage.categories.examples.semigroups as examples
        if choice == "leftzero":
            return examples.LeftZeroSemigroup(**kwds)
        else:
            return examples.FreeSemigroup(**kwds)

    class ParentMethods:

        def _test_associativity(self, **options):
            r"""
            Test associativity for (not necessarily all) elements of this
            semigroup.

            INPUT::

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`

            EXAMPLES:

            By default, this method tests only the elements returned by
            ``self.some_elements()``::

                sage: L = Semigroups().example(choice='leftzero')
                sage: L._test_associativity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L._test_associativity(elements = (L(1), L(2), L(3)))

            See the documentation for :class:`TestSuite` for more information.

            """
            tester = self._tester(**options)
            S = tester.some_elements()
            from sage.combinat.cartesian_product import CartesianProduct
            for x,y,z in tester.some_elements(CartesianProduct(S,S,S)):
                tester.assert_((x * y) * z == x * (y * z))

        def prod(self, args):
            r"""
            Return the product of the list of elements ``args``
            inside ``self``.

            EXAMPLES::

                sage: S = Semigroups().example("free")
                sage: S.prod([S('a'), S('b'), S('c')])
                'abc'
                sage: S.prod([])
                Traceback (most recent call last):
                ...
                AssertionError: Cannot compute an empty product in a semigroup
            """
            assert len(args) > 0, "Cannot compute an empty product in a semigroup"
            return prod(args[1:], args[0])

        def cayley_graph(self, side="right", simple=False, elements = None, generators = None, connecting_set = None):
            r"""
            Return the Cayley graph for this finite semigroup.

            INPUT:

            - ``side`` -- "left", "right", or "twosided":
              the side on which the generators act (default:"right")
            - ``simple`` -- boolean (default:False):
              if True, returns a simple graph (no loops, no labels,
              no multiple edges)
            - ``generators`` -- a list, tuple, or family of elements
              of ``self`` (default: ``self.semigroup_generators()``)
            - ``connecting_set`` -- alias for ``generators``; deprecated
            - ``elements`` -- a list (or iterable) of elements of ``self``

            OUTPUT:

            - :class:`DiGraph`

            EXAMPLES:

            We start with the (right) Cayley graphs of some classical groups::

                sage: D4 = DihedralGroup(4); D4
                Dihedral group of order 8 as a permutation group
                sage: G = D4.cayley_graph()
                sage: show(G, color_by_label=True, edge_labels=True)
                sage: A5 = AlternatingGroup(5); A5
                Alternating group of order 5!/2 as a permutation group
                sage: G = A5.cayley_graph()
                sage: G.show3d(color_by_label=True, edge_size=0.01, edge_size2=0.02, vertex_size=0.03)
                sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1):G.vertices()}, bgcolor=(0,0,0), color_by_label=True, xres=700, yres=700, iterations=200) # long time (less than a minute)
                sage: G.num_edges()
                120

                sage: w = WeylGroup(['A',3])
                sage: d = w.cayley_graph(); d
                Digraph on 24 vertices
                sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03)

            Alternative generators may be specified::

                sage: G = A5.cayley_graph(generators=[A5.gens()[0]])
                sage: G.num_edges()
                60
                sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i])
                sage: g.cayley_graph(generators=[(1,2),(2,3)])
                Digraph on 120 vertices

            If ``elements`` is specified, then only the subgraph
            induced and those elements is returned. Here we use it to
            display the Cayley graph of the free monoid truncated on
            the elements of length at most 3::

                sage: M = Monoids().example(); M
                An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd')
                sage: elements = [ M.prod(w) for w in sum((list(Words(M.semigroup_generators(),k)) for k in range(4)),[]) ]
                sage: G = M.cayley_graph(elements = elements)
                sage: G.num_verts(), G.num_edges()
                (85, 84)
                sage: G.show3d(color_by_label=True, edge_size=0.001, vertex_size=0.01)

            We now illustrate the ``side`` and ``simple`` options on
            a semigroup::

                sage: S = FiniteSemigroups().example(alphabet=('a','b'))
                sage: g = S.cayley_graph(simple=True)
                sage: g.vertices()
                ['a', 'ab', 'b', 'ba']
                sage: g.edges()
                [('a', 'ab', None), ('b', 'ba', None)]

            ::

                sage: g = S.cayley_graph(side="left", simple=True)
                sage: g.vertices()
                ['a', 'ab', 'b', 'ba']
                sage: g.edges()
                [('a', 'ba', None), ('ab', 'ba', None), ('b', 'ab', None),
                ('ba', 'ab', None)]

            ::

                sage: g = S.cayley_graph(side="twosided", simple=True)
                sage: g.vertices()
                ['a', 'ab', 'b', 'ba']
                sage: g.edges()
                [('a', 'ab', None), ('a', 'ba', None), ('ab', 'ba', None),
                ('b', 'ab', None), ('b', 'ba', None), ('ba', 'ab', None)]

            ::

                sage: g = S.cayley_graph(side="twosided")
                sage: g.vertices()
                ['a', 'ab', 'b', 'ba']
                sage: g.edges()
                [('a', 'a', (0, 'left')), ('a', 'a', (0, 'right')), ('a', 'ab', (1, 'right')), ('a', 'ba', (1, 'left')), ('ab', 'ab', (0, 'left')), ('ab', 'ab', (0, 'right')), ('ab', 'ab', (1, 'right')), ('ab', 'ba', (1, 'left')), ('b', 'ab', (0, 'left')), ('b', 'b', (1, 'left')), ('b', 'b', (1, 'right')), ('b', 'ba', (0, 'right')), ('ba', 'ab', (0, 'left')), ('ba', 'ba', (0, 'right')), ('ba', 'ba', (1, 'left')), ('ba', 'ba', (1, 'right'))]

            ::

                sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices()
                [()]

            TESTS::

                sage: SymmetricGroup(2).cayley_graph(side="both")
                Traceback (most recent call last):
                ...
                ValueError: option 'side' must be 'left', 'right' or 'twosided'

            .. TODO::

                - Add more options for constructing subgraphs of the
                  Cayley graph, handling the standard use cases when
                  exploring large/infinite semigroups (a predicate,
                  generators of an ideal, a maximal length in term of the
                  generators)

                - Specify good default layout/plot/latex options in the graph

                - Generalize to combinatorial modules with module generators / operators

            AUTHORS:

            - Bobby Moretti (2007-08-10)
            - Robert Miller (2008-05-01): editing
            - Nicolas M. Thiery (2008-12): extension to semigroups,
              ``side``, ``simple``, and ``elements`` options, ...
            """
            from sage.graphs.digraph import DiGraph
            from groups import Groups
            if not side in ["left", "right", "twosided"]:
                raise ValueError("option 'side' must be 'left', 'right' or 'twosided'")
            if elements is None:
                assert self.is_finite(), "elements should be specified for infinite semigroups"
                elements = list(self)
            elements_set = set(elements)
            if simple or self in Groups():
                result = DiGraph()
            else:
                result = DiGraph(multiedges = True, loops = True)
            result.add_vertices(elements)

            if connecting_set is not None:
                generators = connecting_set
            if generators is None:
                generators = self.semigroup_generators()
            if isinstance(generators, (list, tuple)):
                generators = dict((self(g), self(g)) for g in generators)
            left  = (side == "left"  or side == "twosided")
            right = (side == "right" or side == "twosided")
            def add_edge(source, target, label, side_label):
                """
                Skips edges whose targets are not in elements
                Return an appropriate edge given the options
                """
                if target not in elements_set: return
                if simple:
                    result.add_edge([source, target])
                elif side == "twosided":
                    result.add_edge([source, target, (label, side_label)])
                else:
                    result.add_edge([source, target, label])
            for x in elements:
                for i in generators.keys():
                    if left:
                        add_edge(x, generators[i]*x, i, "left" )
                    if right:
                        add_edge(x, x*generators[i], i, "right")
            return result

    class ElementMethods:

        def _pow_(self, n):
            """
            Return ``self`` to the `n^{th}` power.

            INPUT:

            - ``n`` -- a positive integer

            EXAMPLES::

                sage: S = Semigroups().example("leftzero")
                sage: x = S("x")
                sage: x^1, x^2, x^3, x^4, x^5
                ('x', 'x', 'x', 'x', 'x')
                sage: x^0
                Traceback (most recent call last):
                ...
                AssertionError

            TESTS::

                sage: x._pow_(17)
                'x'

            """
            assert n > 0
            return generic_power(self, n)

        __pow__ = _pow_


    Finite = LazyImport('sage.categories.finite_semigroups', 'FiniteSemigroups', at_startup=True)
    Unital = LazyImport('sage.categories.monoids', 'Monoids', at_startup=True)

    #######################################
    class Subquotients(SubquotientsCategory):
        r"""
        The category of subquotient semi-groups.

        EXAMPLES::

            sage: Semigroups().Subquotients().all_super_categories()
            [Category of subquotients of semigroups,
             Category of semigroups,
             Category of subquotients of magmas,
             Category of magmas,
             Category of subquotients of sets,
             Category of sets,
             Category of sets with partial maps,
             Category of objects]

            [Category of subquotients of semigroups,
             Category of semigroups,
             Category of subquotients of magmas,
             Category of magmas,
             Category of subquotients of sets,
             Category of sets,
             Category of sets with partial maps,
             Category of objects]
        """

        def example(self):
            """
            Returns an example of subquotient of a semigroup, as per
            :meth:`Category.example()
            <sage.categories.category.Category.example>`.

            EXAMPLES::

                sage: Semigroups().Subquotients().example()
                An example of a (sub)quotient semigroup: a quotient of the left zero semigroup
            """
            from sage.categories.examples.semigroups import QuotientOfLeftZeroSemigroup
            return QuotientOfLeftZeroSemigroup(category = self.Subquotients())

    class Quotients(QuotientsCategory):

        def example(self):
            r"""
            Return an example of quotient of a semigroup, as per
            :meth:`Category.example()
            <sage.categories.category.Category.example>`.

            EXAMPLES::

                sage: Semigroups().Quotients().example()
                An example of a (sub)quotient semigroup: a quotient of the left zero semigroup
            """
            from sage.categories.examples.semigroups import QuotientOfLeftZeroSemigroup
            return QuotientOfLeftZeroSemigroup()

        class ParentMethods:

            def semigroup_generators(self):
                r"""
                Return semigroup generators for ``self`` by
                retracting the semigroup generators of the ambient
                semigroup.

                EXAMPLES::

                    sage: S = FiniteSemigroups().Quotients().example().semigroup_generators() # todo: not implemented
                """
                return self.ambient().semigroup_generators().map(self.retract)

    class CartesianProducts(CartesianProductsCategory):

        def extra_super_categories(self):
            """
            Implement the fact that a cartesian product of semigroups is a
            semigroup.

            EXAMPLES::

                sage: Semigroups().CartesianProducts().extra_super_categories()
                [Category of semigroups]
                sage: Semigroups().CartesianProducts().super_categories()
                [Category of semigroups, Category of Cartesian products of magmas]
            """
            return [Semigroups()]

    class Algebras(AlgebrasCategory):
        """
        TESTS::

            sage: TestSuite(Semigroups().Algebras(QQ)).run()
            sage: TestSuite(Semigroups().Finite().Algebras(QQ)).run()
        """

        def extra_super_categories(self):
            """
            Implement the fact that the algebra of a semigroup is indeed
            a (not necessarily unital) algebra.

            EXAMPLES::

                sage: Semigroups().Algebras(QQ).extra_super_categories()
                [Category of semigroups]
                sage: Semigroups().Algebras(QQ).super_categories()
                [Category of associative algebras over Rational Field,
                 Category of magma algebras over Rational Field]
            """
            return [Semigroups()]

        class ParentMethods:

            @cached_method
            def algebra_generators(self):
                r"""
                The generators of this algebra, as per
                :meth:`MagmaticAlgebras.ParentMethods.algebra_generators()
                <.magmatic_algebras.MagmaticAlgebras.ParentMethods.algebra_generators>`.

                They correspond to the generators of the semigroup.

                EXAMPLES::

                    sage: A = FiniteSemigroups().example().algebra(ZZ)
                    sage: A.algebra_generators()
                    Finite family {0: B['a'], 1: B['b'], 2: B['c'], 3: B['d']}
                """
                return self.basis().keys().semigroup_generators().map(self.monomial)

            def product_on_basis(self, g1, g2):
                r"""
                Product, on basis elements, as per
                :meth:`MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis()
                <.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis>`.

                The product of two basis elements is induced by the
                product of the corresponding elements of the group.

                EXAMPLES::

                    sage: S = FiniteSemigroups().example(); S
                    An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd')
                    sage: A = S.algebra(QQ)
                    sage: a,b,c,d = A.algebra_generators()
                    sage: a * b + b * d * c * d
                    B['ab'] + B['bdc']
                """
                return self.monomial(g1 * g2)
Ejemplo n.º 12
0
class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring):
    """
    The category of algebras with a distinguished basis.

    EXAMPLES::

        sage: C = AlgebrasWithBasis(QQ); C
        Category of algebras with basis over Rational Field
        sage: sorted(C.super_categories(), key=str)
        [Category of algebras over Rational Field,
         Category of unital algebras with basis over Rational Field]

    We construct a typical parent in this category, and do some
    computations with it::

        sage: A = C.example(); A
        An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field

        sage: A.category()
        Category of algebras with basis over Rational Field

        sage: A.one_basis()
        word:
        sage: A.one()
        B[word: ]

        sage: A.base_ring()
        Rational Field
        sage: A.basis().keys()
        Finite words over {'a', 'b', 'c'}

        sage: (a,b,c) = A.algebra_generators()
        sage: a^3, b^2
        (B[word: aaa], B[word: bb])
        sage: a*c*b
        B[word: acb]

        sage: A.product
        <bound method FreeAlgebra_with_category._product_from_product_on_basis_multiply of
         An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field>
        sage: A.product(a*b,b)
        B[word: abb]

        sage: TestSuite(A).run(verbose=True)
        running ._test_additive_associativity() . . . pass
        running ._test_an_element() . . . pass
        running ._test_associativity() . . . pass
        running ._test_cardinality() . . . pass
        running ._test_category() . . . pass
        running ._test_characteristic() . . . pass
        running ._test_distributivity() . . . pass
        running ._test_elements() . . .
          Running the test suite of self.an_element()
          running ._test_category() . . . pass
          running ._test_eq() . . . pass
          running ._test_new() . . . pass
          running ._test_nonzero_equal() . . . pass
          running ._test_not_implemented_methods() . . . pass
          running ._test_pickling() . . . pass
          pass
        running ._test_elements_eq_reflexive() . . . pass
        running ._test_elements_eq_symmetric() . . . pass
        running ._test_elements_eq_transitive() . . . pass
        running ._test_elements_neq() . . . pass
        running ._test_eq() . . . pass
        running ._test_new() . . . pass
        running ._test_not_implemented_methods() . . . pass
        running ._test_one() . . . pass
        running ._test_pickling() . . . pass
        running ._test_prod() . . . pass
        running ._test_some_elements() . . . pass
        running ._test_zero() . . . pass
        sage: A.__class__
        <class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category'>
        sage: A.element_class
        <class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category.element_class'>

    Please see the source code of `A` (with ``A??``) for how to
    implement other algebras with basis.

    TESTS::

        sage: TestSuite(AlgebrasWithBasis(QQ)).run()
    """
    def example(self, alphabet=('a', 'b', 'c')):
        """
        Return an example of algebra with basis.

        EXAMPLES::

            sage: AlgebrasWithBasis(QQ).example()
            An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field

        An other set of generators can be specified as optional argument::

            sage: AlgebrasWithBasis(QQ).example((1,2,3))
            An example of an algebra with basis: the free algebra on the generators (1, 2, 3) over Rational Field
        """
        from sage.categories.examples.algebras_with_basis import Example
        return Example(self.base_ring(), alphabet)

    Filtered = LazyImport('sage.categories.filtered_algebras_with_basis',
                          'FilteredAlgebrasWithBasis')
    FiniteDimensional = LazyImport(
        'sage.categories.finite_dimensional_algebras_with_basis',
        'FiniteDimensionalAlgebrasWithBasis',
        at_startup=True)
    Graded = LazyImport('sage.categories.graded_algebras_with_basis',
                        'GradedAlgebrasWithBasis')
    Super = LazyImport('sage.categories.super_algebras_with_basis',
                       'SuperAlgebrasWithBasis')

    class ParentMethods:

        # For backward compatibility
        one = UnitalAlgebras.WithBasis.ParentMethods.one

        # Backward compatibility temporary cruft to help migrating form CombinatorialAlgebra
        def _product_from_combinatorial_algebra_multiply(self, left, right):
            r"""
            Returns left\*right where left and right are elements of self.
            product() uses either _multiply or _multiply basis to carry out
            the actual multiplication.

            EXAMPLES::

                sage: s = SymmetricFunctions(QQ).schur()
                sage: a = s([2])
                sage: s._product_from_combinatorial_algebra_multiply(a,a)
                s[2, 2] + s[3, 1] + s[4]
                sage: s.product(a,a)
                s[2, 2] + s[3, 1] + s[4]
            """
            A = left.parent()
            BR = A.base_ring()
            z_elt = {}

            #Do the case where the user specifies how to multiply basis elements
            if hasattr(self, '_multiply_basis'):
                for (left_m,
                     left_c) in six.iteritems(left._monomial_coefficients):
                    for (right_m, right_c) in six.iteritems(
                            right._monomial_coefficients):
                        res = self._multiply_basis(left_m, right_m)
                        #Handle the case where the user returns a dictionary
                        #where the keys are the monomials and the values are
                        #the coefficients.  If res is not a dictionary, then
                        #it is assumed to be an element of self
                        if not isinstance(res, dict):
                            if isinstance(res, self._element_class):
                                res = res._monomial_coefficients
                            else:
                                res = {res: BR(1)}
                        for m in res:
                            if m in z_elt:
                                z_elt[m] = z_elt[m] + left_c * right_c * res[m]
                            else:
                                z_elt[m] = left_c * right_c * res[m]

            #We assume that the user handles the multiplication correctly on
            #his or her own, and returns a dict with monomials as keys and
            #coefficients as values
            else:
                m = self._multiply(left, right)
                if isinstance(m, self._element_class):
                    return m
                if not isinstance(m, dict):
                    z_elt = m.monomial_coefficients()
                else:
                    z_elt = m

            #Remove all entries that are equal to 0
            BR = self.base_ring()
            zero = BR(0)
            del_list = []
            for m, c in six.iteritems(z_elt):
                if c == zero:
                    del_list.append(m)
            for m in del_list:
                del z_elt[m]

            return self._from_dict(z_elt)

        #def _test_product(self, **options):
        #    tester = self._tester(**options)
        #    tester.assertTrue(self.product is not None)
        #    could check that self.product is in Hom( self x self, self)

        def hochschild_complex(self, M):
            """
            Return the Hochschild complex of ``self`` with coefficients
            in ``M``.

            .. SEEALSO::

                :class:`~sage.homology.hochschild_complex.HochschildComplex`

            EXAMPLES::

                sage: R.<x> = QQ[]
                sage: A = algebras.DifferentialWeyl(R)
                sage: H = A.hochschild_complex(A)

                sage: SGA = SymmetricGroupAlgebra(QQ, 3)
                sage: T = SGA.trivial_representation()
                sage: H = SGA.hochschild_complex(T)
            """
            from sage.homology.hochschild_complex import HochschildComplex
            return HochschildComplex(self, M)

    class ElementMethods:
        def __invert__(self):
            """
            Return the inverse of ``self`` if ``self`` is a multiple of one,
            and one is in the basis of this algebra. Otherwise throws
            an error.

            Caveat: this generic implementation is not complete; there
            may be invertible elements in the algebra that can't be
            inversed this way. It is correct though for graded
            connected algebras with basis.

            .. WARNING::

                This might produce a result which does not belong to
                the parent of ``self``, yet believes to do so. For
                instance, inverting 2 times the unity will produce 1/2
                times the unity, even if 1/2 is not in the base ring.
                Handle with care.

            EXAMPLES::

                sage: C = AlgebrasWithBasis(QQ).example()
                sage: x = C(2); x
                2*B[word: ]
                sage: ~x
                1/2*B[word: ]
                sage: a = C.algebra_generators().first(); a
                B[word: a]
                sage: ~a
                Traceback (most recent call last):
                ...
                ValueError: cannot invert self (= B[word: a])
            """
            # FIXME: make this generic
            mcs = self.monomial_coefficients(copy=False)
            one = self.parent().one_basis()
            if len(mcs) == 1 and one in mcs:
                return self.parent().term(one, ~mcs[one])
            else:
                raise ValueError("cannot invert self (= %s)" % self)

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of algebras with basis, constructed as Cartesian
        products of algebras with basis.

        Note: this construction give the direct products of algebras with basis.
        See comment in :class:`Algebras.CartesianProducts
        <sage.categories.algebras.Algebras.CartesianProducts>`
        """
        def extra_super_categories(self):
            """
            A Cartesian product of algebras with basis is endowed with
            a natural algebra with basis structure.

            EXAMPLES::

                sage: AlgebrasWithBasis(QQ).CartesianProducts().extra_super_categories()
                [Category of algebras with basis over Rational Field]
                sage: AlgebrasWithBasis(QQ).CartesianProducts().super_categories()
                [Category of algebras with basis over Rational Field,
                 Category of Cartesian products of algebras over Rational Field,
                 Category of Cartesian products of vector spaces with basis over Rational Field]
            """
            return [self.base_category()]

        class ParentMethods:
            @cached_method
            def one_from_cartesian_product_of_one_basis(self):
                """
                Returns the one of this Cartesian product of algebras, as per ``Monoids.ParentMethods.one``

                It is constructed as the Cartesian product of the ones of the
                summands, using their :meth:`~AlgebrasWithBasis.ParentMethods.one_basis` methods.

                This implementation does not require multiplication by
                scalars nor calling cartesian_product. This might help keeping
                things as lazy as possible upon initialization.

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example(); A
                    An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                    sage: A.one_basis()
                    word:

                    sage: B = cartesian_product((A, A, A))
                    sage: B.one_from_cartesian_product_of_one_basis()
                    B[(0, word: )] + B[(1, word: )] + B[(2, word: )]
                    sage: B.one()
                    B[(0, word: )] + B[(1, word: )] + B[(2, word: )]

                    sage: cartesian_product([SymmetricGroupAlgebra(QQ, 3), SymmetricGroupAlgebra(QQ, 4)]).one()
                    B[(0, [1, 2, 3])] + B[(1, [1, 2, 3, 4])]
                """
                return self.sum_of_monomials(
                    zip(self._sets_keys(),
                        (set.one_basis() for set in self._sets)))

            @lazy_attribute
            def one(self):
                """
                TESTS::

                    sage: A = AlgebrasWithBasis(QQ).example(); A
                    An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                    sage: B = cartesian_product((A, A, A))
                    sage: B.one()
                    B[(0, word: )] + B[(1, word: )] + B[(2, word: )]
                """
                if all(hasattr(module, "one_basis") for module in self._sets):
                    return self.one_from_cartesian_product_of_one_basis
                else:
                    return NotImplemented

            #def product_on_basis(self, t1, t2):
            # would be easy to implement, but without a special
            # version of module morphism, this would not take
            # advantage of the bloc structure

    class TensorProducts(TensorProductsCategory):
        """
        The category of algebras with basis constructed by tensor product of algebras with basis
        """
        @cached_method
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: AlgebrasWithBasis(QQ).TensorProducts().extra_super_categories()
                [Category of algebras with basis over Rational Field]
                sage: AlgebrasWithBasis(QQ).TensorProducts().super_categories()
                [Category of algebras with basis over Rational Field,
                 Category of tensor products of algebras over Rational Field,
                 Category of tensor products of vector spaces with basis over Rational Field]
            """
            return [self.base_category()]

        class ParentMethods:
            """
            implements operations on tensor products of algebras with basis
            """
            @cached_method
            def one_basis(self):
                """
                Returns the index of the one of this tensor product of
                algebras, as per ``AlgebrasWithBasis.ParentMethods.one_basis``

                It is the tuple whose operands are the indices of the
                ones of the operands, as returned by their
                :meth:`.one_basis` methods.

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example(); A
                    An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                    sage: A.one_basis()
                    word:
                    sage: B = tensor((A, A, A))
                    sage: B.one_basis()
                    (word: , word: , word: )
                    sage: B.one()
                    B[word: ] # B[word: ] # B[word: ]
                """
                # FIXME: this method should be conditionally defined,
                # so that B.one_basis returns NotImplemented if not
                # all modules provide one_basis
                if all(hasattr(module, "one_basis") for module in self._sets):
                    return tuple(module.one_basis() for module in self._sets)
                else:
                    raise NotImplementedError

            def product_on_basis(self, t1, t2):
                """
                The product of the algebra on the basis, as per
                ``AlgebrasWithBasis.ParentMethods.product_on_basis``.

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example(); A
                    An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                    sage: (a,b,c) = A.algebra_generators()

                    sage: x = tensor( (a, b, c) ); x
                    B[word: a] # B[word: b] # B[word: c]
                    sage: y = tensor( (c, b, a) ); y
                    B[word: c] # B[word: b] # B[word: a]
                    sage: x*y
                    B[word: ac] # B[word: bb] # B[word: ca]

                    sage: x = tensor( ((a+2*b), c) )    ; x
                    B[word: a] # B[word: c] + 2*B[word: b] # B[word: c]
                    sage: y = tensor( (c,       a) ) + 1; y
                    B[word: ] # B[word: ] + B[word: c] # B[word: a]
                    sage: x*y
                    B[word: a] # B[word: c] + B[word: ac] # B[word: ca] + 2*B[word: b] # B[word: c] + 2*B[word: bc] # B[word: ca]


                TODO: optimize this implementation!
                """
                return tensor(
                    (module.monomial(x1) * module.monomial(x2)
                     for (module, x1, x2) in zip(self._sets, t1, t2)))  #.

        class ElementMethods:
            """
            Implements operations on elements of tensor products of algebras with basis
            """
            pass
Ejemplo n.º 13
0
class LieAlgebras(Category_over_base_ring):
    """
    The category of Lie algebras.

    EXAMPLES::

        sage: C = LieAlgebras(QQ); C
        Category of Lie algebras over Rational Field
        sage: sorted(C.super_categories(), key=str)
        [Category of vector spaces over Rational Field]

    We construct a typical parent in this category, and do some
    computations with it::

        sage: A = C.example(); A
        An example of a Lie algebra: the Lie algebra from the associative
         algebra Symmetric group algebra of order 3 over Rational Field
         generated by ([2, 1, 3], [2, 3, 1])

        sage: A.category()
        Category of Lie algebras over Rational Field

        sage: A.base_ring()
        Rational Field

        sage: a,b = A.lie_algebra_generators()
        sage: a.bracket(b)
        -[1, 3, 2] + [3, 2, 1]
        sage: b.bracket(2*a + b)
        2*[1, 3, 2] - 2*[3, 2, 1]

        sage: A.bracket(a, b)
        -[1, 3, 2] + [3, 2, 1]

    Please see the source code of `A` (with ``A??``) for how to
    implement other Lie algebras.

    TESTS::

        sage: C = LieAlgebras(QQ)
        sage: TestSuite(C).run()
        sage: TestSuite(C.example()).run()

    .. TODO::

        Many of these tests should use Lie algebras that are not the minimal
        example and need to be added after :trac:`16820` (and :trac:`16823`).
    """
    @cached_method
    def super_categories(self):
        """
        EXAMPLES::

            sage: LieAlgebras(QQ).super_categories()
            [Category of vector spaces over Rational Field]
        """
        # We do not also derive from (Magmatic) algebras since we don't want *
        #   to be our Lie bracket
        # Also this doesn't inherit the ability to add axioms like Associative
        #   and Unital, both of which do not make sense for Lie algebras
        return [Modules(self.base_ring())]

    # TODO: Find some way to do this without copying most of the logic.
    def _repr_object_names(self):
        r"""
        Return the name of the objects of this category.

        .. SEEALSO:: :meth:`Category._repr_object_names`

        EXAMPLES::

            sage: LieAlgebras(QQ)._repr_object_names()
            'Lie algebras over Rational Field'
            sage: LieAlgebras(Fields())._repr_object_names()
            'Lie algebras over fields'
            sage: from sage.categories.category import JoinCategory
            sage: from sage.categories.category_with_axiom import Blahs
            sage: LieAlgebras(JoinCategory((Blahs().Flying(), Fields())))
            Category of Lie algebras over (flying unital blahs and fields)
        """
        base = self.base()
        if isinstance(base, Category):
            if isinstance(base, JoinCategory):
                name = '(' + ' and '.join(
                    C._repr_object_names()
                    for C in base.super_categories()) + ')'
            else:
                name = base._repr_object_names()
        else:
            name = base
        return "Lie algebras over {}".format(name)

    def example(self, gens=None):
        """
        Return an example of a Lie algebra as per
        :meth:`Category.example <sage.categories.category.Category.example>`.

        EXAMPLES::

            sage: LieAlgebras(QQ).example()
            An example of a Lie algebra: the Lie algebra from the associative algebra
             Symmetric group algebra of order 3 over Rational Field
             generated by ([2, 1, 3], [2, 3, 1])

        Another set of generators can be specified as an optional argument::

            sage: F.<x,y,z> = FreeAlgebra(QQ)
            sage: LieAlgebras(QQ).example(F.gens())
            An example of a Lie algebra: the Lie algebra from the associative algebra
             Free Algebra on 3 generators (x, y, z) over Rational Field
             generated by (x, y, z)
        """
        if gens is None:
            from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
            from sage.rings.all import QQ
            gens = SymmetricGroupAlgebra(QQ, 3).algebra_generators()
        from sage.categories.examples.lie_algebras import Example
        return Example(gens)

    WithBasis = LazyImport('sage.categories.lie_algebras_with_basis',
                           'LieAlgebrasWithBasis',
                           as_name='WithBasis')

    class FiniteDimensional(CategoryWithAxiom_over_base_ring):
        WithBasis = LazyImport(
            'sage.categories.finite_dimensional_lie_algebras_with_basis',
            'FiniteDimensionalLieAlgebrasWithBasis',
            as_name='WithBasis')

        def extra_super_categories(self):
            """
            Implements the fact that a finite dimensional Lie algebra over
            a finite ring is finite.

            EXAMPLES::

                sage: LieAlgebras(IntegerModRing(4)).FiniteDimensional().extra_super_categories()
                [Category of finite sets]
                sage: LieAlgebras(ZZ).FiniteDimensional().extra_super_categories()
                []
                sage: LieAlgebras(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite())
                True
                sage: LieAlgebras(ZZ).FiniteDimensional().is_subcategory(Sets().Finite())
                False
                sage: LieAlgebras(GF(5)).WithBasis().FiniteDimensional().is_subcategory(Sets().Finite())
                True
            """
            if self.base_ring() in Sets().Finite():
                return [Sets().Finite()]
            return []

    class ParentMethods:
        #@abstract_method
        #def lie_algebra_generators(self):
        #    """
        #    Return the generators of ``self`` as a Lie algebra.
        #    """

        # TODO: Move this to LieAlgebraElement, cythonize, and use more standard
        #   coercion framework test (i.e., have_same_parent)
        def bracket(self, lhs, rhs):
            """
            Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and
            ``rhs`` into elements of ``self``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.bracket(x, x + y)
                -[1, 3, 2] + [3, 2, 1]
                sage: L.bracket(x, 0)
                0
                sage: L.bracket(0, x)
                0
            """
            return self(lhs)._bracket_(self(rhs))

        # Do not override this. Instead implement :meth:`_construct_UEA`;
        #   then, :meth:`lift` and :meth:`universal_enveloping_algebra`
        #   will automatically setup the coercion.
        def universal_enveloping_algebra(self):
            """
            Return the universal enveloping algebra of ``self``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.universal_enveloping_algebra()
                Noncommutative Multivariate Polynomial Ring in b0, b1, b2
                 over Rational Field, nc-relations: {}

            ::

                sage: L = LieAlgebra(QQ, 3, 'x', abelian=True)
                sage: L.universal_enveloping_algebra()
                Multivariate Polynomial Ring in x0, x1, x2 over Rational Field

            .. SEEALSO::

                :meth:`lift`
            """
            return self.lift.codomain()

        @abstract_method(optional=True)
        def _construct_UEA(self):
            """
            Return the universal enveloping algebra of ``self``.

            Unlike :meth:`universal_enveloping_algebra`, this method does not
            (usually) construct the canonical lift morphism from ``self``
            to the universal enveloping algebra (let alone register it
            as a coercion).

            One should implement this method and the ``lift`` method for
            the element class to construct the morphism the universal
            enveloping algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L._construct_UEA()
                Noncommutative Multivariate Polynomial Ring in b0, b1, b2
                 over Rational Field, nc-relations: {}

            ::

                sage: L = LieAlgebra(QQ, 3, 'x', abelian=True)
                sage: L.universal_enveloping_algebra() # indirect doctest
                Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
            """

        @abstract_method(optional=True)
        def module(self):
            r"""
            Return an `R`-module which is isomorphic to the
            underlying `R`-module of ``self``.

            The rationale behind this method is to enable linear
            algebraic functionality on ``self`` (such as
            computing the span of a list of vectors in ``self``)
            via an isomorphism from ``self`` to an `R`-module
            (typically, although not always, an `R`-module of
            the form `R^n` for an `n \in \NN`) on which such
            functionality already exists. For this method to be
            of any use, it should return an `R`-module which has
            linear algebraic functionality that ``self`` does
            not have.

            For instance, if ``self`` has ordered basis
            `(e, f, h)`, then ``self.module()`` will be the
            `R`-module `R^3`, and the elements `e`, `f` and
            `h` of ``self`` will correspond to the basis
            vectors `(1, 0, 0)`, `(0, 1, 0)` and `(0, 0, 1)`
            of ``self.module()``.

            This method :meth:`module` needs to be set whenever
            a finite-dimensional Lie algebra with basis is
            intended to support linear algebra (which is, e.g.,
            used in the computation of centralizers and lower
            central series). One then needs to also implement
            the `R`-module isomorphism from ``self`` to
            ``self.module()`` in both directions; that is,
            implement:

            * a ``to_vector`` ElementMethod which sends every
              element of ``self`` to the corresponding element of
              ``self.module()``;

            * a ``from_vector`` ParentMethod which sends every
              element of ``self.module()`` to an element
              of ``self``.

            The ``from_vector`` method will automatically serve
            as an element constructor of ``self`` (that is,
            ``self(v)`` for any ``v`` in ``self.module()`` will
            return ``self.from_vector(v)``).

            .. TODO::

                Ensure that this is actually so.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.module()
                Vector space of dimension 3 over Rational Field
            """

        @abstract_method(optional=True)
        def from_vector(self, v):
            """
            Return the element of ``self`` corresponding to the
            vector ``v`` in ``self.module()``.

            Implement this if you implement :meth:`module`; see the
            documentation of the latter for how this is to be done.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u
                (1, 0, 0)
                sage: parent(u) is L
                True
            """

        @lazy_attribute
        def lift(self):
            r"""
            Construct the lift morphism from ``self`` to the universal
            enveloping algebra of ``self`` (the latter is implemented
            as :meth:`universal_enveloping_algebra`).

            This is a Lie algebra homomorphism. It is injective if
            ``self`` is a free module over its base ring, or if the
            base ring is a `\QQ`-algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: lifted = L.lift(2*a + b - c); lifted
                2*b0 + b1 - b2
                sage: lifted.parent() is L.universal_enveloping_algebra()
                True
            """
            M = LiftMorphism(self, self._construct_UEA())
            M.register_as_coercion()
            return M

        def subalgebra(self, gens, names=None, index_set=None, category=None):
            r"""
            Return the subalgebra of ``self`` generated by ``gens``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.subalgebra([2*a - c, b + c])
                An example of a finite dimensional Lie algebra with basis:
                 the 2-dimensional abelian Lie algebra over Rational Field
                 with basis matrix:
                [   1    0 -1/2]
                [   0    1    1]

            ::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.subalgebra([x + y])
                Traceback (most recent call last):
                ...
                NotImplementedError: subalgebras not yet implemented: see #17416
            """
            raise NotImplementedError(
                "subalgebras not yet implemented: see #17416")
            #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra
            #return LieSubalgebra(gens, names, index_set, category)

        def ideal(self, gens, names=None, index_set=None, category=None):
            r"""
            Return the ideal of ``self`` generated by ``gens``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.ideal([2*a - c, b + c])
                An example of a finite dimensional Lie algebra with basis:
                 the 2-dimensional abelian Lie algebra over Rational Field
                 with basis matrix:
                [   1    0 -1/2]
                [   0    1    1]

            ::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.ideal([x + y])
                Traceback (most recent call last):
                ...
                NotImplementedError: ideals not yet implemented: see #16824
            """
            raise NotImplementedError("ideals not yet implemented: see #16824")
            #from sage.algebras.lie_algebras.ideal import LieIdeal
            #return LieIdeal(gens, names, index_set, category)

        def is_ideal(self, A):
            """
            Return if ``self`` is an ideal of ``A``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_ideal(L)
                True
            """
            if A == self:
                return True
            raise NotImplementedError("ideals not yet implemented: see #16824")
            #from sage.algebras.lie_algebras.ideal import LieIdeal
            #return isinstance(self, LieIdeal) and self._ambient is A

        @abstract_method(optional=True)
        def killing_form(self, x, y):
            """
            Return the Killing form of ``x`` and ``y``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.killing_form(a, b+c)
                0
            """

        def is_abelian(self):
            r"""
            Return ``True`` if this Lie algebra is abelian.

            A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all
            `x, y \in \mathfrak{g}`.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_abelian()
                False
                sage: R = QQ['x,y']
                sage: L = LieAlgebras(QQ).example(R.gens())
                sage: L.is_abelian()
                True

            ::

                sage: L.<x> = LieAlgebra(QQ,1)  # todo: not implemented - #16823
                sage: L.is_abelian()  # todo: not implemented - #16823
                True
                sage: L.<x,y> = LieAlgebra(QQ,2)  # todo: not implemented - #16823
                sage: L.is_abelian()  # todo: not implemented - #16823
                False
            """
            G = self.lie_algebra_generators()
            if G not in FiniteEnumeratedSets():
                raise NotImplementedError("infinite number of generators")
            zero = self.zero()
            return all(x._bracket_(y) == zero for x in G for y in G)

        def is_commutative(self):
            """
            Return if ``self`` is commutative. This is equivalent to ``self``
            being abelian.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_commutative()
                False

            ::

                sage: L.<x> = LieAlgebra(QQ, 1) # todo: not implemented - #16823
                sage: L.is_commutative() # todo: not implemented - #16823
                True
            """
            return self.is_abelian()

        @abstract_method(optional=True)
        def is_solvable(self):
            """
            Return if ``self`` is a solvable Lie algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.is_solvable()
                True
            """

        @abstract_method(optional=True)
        def is_nilpotent(self):
            """
            Return if ``self`` is a nilpotent Lie algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.is_nilpotent()
                True
            """

        def _test_jacobi_identity(self, **options):
            """
            Test that the Jacobi identity is satisfied on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_jacobi_identity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L._test_jacobi_identity(elements=[x+y, x, 2*y, x.bracket(y)])

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            elts = tester.some_elements()
            jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \
                self.bracket(y, self.bracket(z, x)) + \
                self.bracket(z, self.bracket(x, y))
            zero = self.zero()
            for x in elts:
                for y in elts:
                    if x == y:
                        continue
                    for z in elts:
                        tester.assertTrue(jacobi(x, y, z) == zero)

        def _test_antisymmetry(self, **options):
            """
            Test that the antisymmetry axiom is satisfied on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_antisymmetry()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L._test_antisymmetry(elements=[x+y, x, 2*y, x.bracket(y)])

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            elts = tester.some_elements()
            zero = self.zero()
            for x in elts:
                tester.assertTrue(self.bracket(x, x) == zero)

        def _test_distributivity(self, **options):
            r"""
            Test the distributivity of the Lie bracket `[,]` on `+` on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            TESTS::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_distributivity()

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebra(QQ, 3, 'x,y,z', representation="polynomial")
                sage: L.some_elements()
                [x + y + z]
                sage: L._test_distributivity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # todo: not implemented - #16821
                sage: h1 = L.gen(0) # todo: not implemented - #16821
                sage: h2 = L.gen(1) # todo: not implemented - #16821
                sage: e2 = L.gen(3) # todo: not implemented - #16821
                sage: L._test_distributivity(elements=[h1, h2, e2]) # todo: not implemented - #16821

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            S = tester.some_elements()
            from sage.misc.misc import some_tuples
            for x, y, z in some_tuples(S, 3, tester._max_runs):
                # left distributivity
                tester.assertTrue(
                    self.bracket(x, (y + z)) == self.bracket(x, y) +
                    self.bracket(x, z))
                # right distributivity
                tester.assertTrue(
                    self.bracket((x + y), z) == self.bracket(x, z) +
                    self.bracket(y, z))

    class ElementMethods:
        @coerce_binop
        def bracket(self, rhs):
            """
            Return the Lie bracket ``[self, rhs]``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: x.bracket(y)
                -[1, 3, 2] + [3, 2, 1]
                sage: x.bracket(0)
                0
            """
            return self._bracket_(rhs)

        # Implement this method to define the Lie bracket. You do not
        # need to deal with the coercions here.
        @abstract_method
        def _bracket_(self, y):
            """
            Return the Lie bracket ``[self, y]``, where ``y`` is an
            element of the same Lie algebra as ``self``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: x._bracket_(y)
                -[1, 3, 2] + [3, 2, 1]
                sage: y._bracket_(x)
                [1, 3, 2] - [3, 2, 1]
                sage: x._bracket_(x)
                0
            """

        @abstract_method(optional=True)
        def to_vector(self):
            """
            Return the vector in ``g.module()`` corresponding to the
            element ``self`` of ``g`` (where ``g`` is the parent of
            ``self``).

            Implement this if you implement ``g.module()``.
            See :meth:`LieAlgebras.module` for how this is to be done.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: u = L((1, 0, 0)).to_vector(); u
                (1, 0, 0)
                sage: parent(u)
                Vector space of dimension 3 over Rational Field
            """

        @abstract_method(optional=True)
        def lift(self):
            """
            Return the image of ``self`` under the canonical lift from the Lie
            algebra to its universal enveloping algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: elt = 3*a + b - c
                sage: elt.lift()
                3*b0 + b1 - b2

            ::

                sage: L.<x,y> = LieAlgebra(QQ, abelian=True)
                sage: x.lift()
                x
            """

        def killing_form(self, x):
            """
            Return the Killing form of ``self`` and ``x``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: a.killing_form(b)
                0
            """
            return self.parent().killing_form(self, x)
Ejemplo n.º 14
0
class AdditiveMagmas(Category_singleton):
    """
    The category of additive magmas.

    An additive magma is a set endowed with a binary operation `+`.

    EXAMPLES::

        sage: AdditiveMagmas()
        Category of additive magmas
        sage: AdditiveMagmas().super_categories()
        [Category of sets]
        sage: AdditiveMagmas().all_super_categories()
        [Category of additive magmas, Category of sets, Category of sets with partial maps, Category of objects]

    The following axioms are defined by this category::

        sage: AdditiveMagmas().AdditiveAssociative()
        Category of additive semigroups
        sage: AdditiveMagmas().AdditiveUnital()
        Category of additive unital additive magmas
        sage: AdditiveMagmas().AdditiveCommutative()
        Category of additive commutative additive magmas
        sage: AdditiveMagmas().AdditiveUnital().AdditiveInverse()
        Category of additive inverse additive unital additive magmas
        sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative()
        Category of commutative additive semigroups
        sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative().AdditiveUnital()
        Category of commutative additive monoids
        sage: AdditiveMagmas().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse()
        Category of commutative additive groups

    TESTS::

        sage: C = AdditiveMagmas()
        sage: TestSuite(C).run()

    """
    def super_categories(self):
        """
        EXAMPLES::

            sage: AdditiveMagmas().super_categories()
            [Category of sets]
        """
        return [Sets()]

    class SubcategoryMethods:
        @cached_method
        def AdditiveAssociative(self):
            r"""
            Return the full subcategory of the additive associative
            objects of ``self``.

            An :class:`additive magma <AdditiveMagmas>` `M` is
            *associative* if, for all `x,y,z \in M`,

            .. MATH:: x + (y + z) = (x + y) + z

            .. SEEALSO:: :wikipedia:`Associative_property`

            EXAMPLES::

                sage: AdditiveMagmas().AdditiveAssociative()
                Category of additive semigroups

            TESTS::

                sage: TestSuite(AdditiveMagmas().AdditiveAssociative()).run()
                sage: Rings().AdditiveAssociative.__module__
                'sage.categories.additive_magmas'
            """
            return self._with_axiom('AdditiveAssociative')

        @cached_method
        def AdditiveCommutative(self):
            r"""
            Return the full subcategory of the commutative objects of ``self``.

            An :class:`additive magma <AdditiveMagmas>` `M` is
            *commutative* if, for all `x,y \in M`,

            .. MATH:: x + y = y + x

            .. SEEALSO:: :wikipedia:`Commutative_property`

            EXAMPLES::

                sage: AdditiveMagmas().AdditiveCommutative()
                Category of additive commutative additive magmas
                sage: AdditiveMagmas().AdditiveAssociative().AdditiveUnital().AdditiveCommutative()
                Category of commutative additive monoids
                sage: _ is CommutativeAdditiveMonoids()
                True

            TESTS::

                sage: TestSuite(AdditiveMagmas().AdditiveCommutative()).run()
                sage: Rings().AdditiveCommutative.__module__
                'sage.categories.additive_magmas'
            """
            return self._with_axiom('AdditiveCommutative')

        @cached_method
        def AdditiveUnital(self):
            r"""
            Return the subcategory of the unital objects of ``self``.

            An :class:`additive magma <AdditiveMagmas>` `M` is *unital*
            if it admits an element `0`, called *neutral element*,
            such that for all `x \in M`,

            .. MATH:: 0 + x = x + 0 = x

            This element is necessarily unique, and should be provided
            as ``M.zero()``.

            .. SEEALSO:: :wikipedia:`Unital_magma#unital`

            EXAMPLES::

                sage: AdditiveMagmas().AdditiveUnital()
                Category of additive unital additive magmas
                sage: from sage.categories.additive_semigroups import AdditiveSemigroups
                sage: AdditiveSemigroups().AdditiveUnital()
                Category of additive monoids
                sage: CommutativeAdditiveMonoids().AdditiveUnital()
                Category of commutative additive monoids

            TESTS::

                sage: TestSuite(AdditiveMagmas().AdditiveUnital()).run()
                sage: CommutativeAdditiveSemigroups().AdditiveUnital.__module__
                'sage.categories.additive_magmas'
            """
            return self._with_axiom("AdditiveUnital")

    AdditiveAssociative = LazyImport('sage.categories.additive_semigroups',
                                     'AdditiveSemigroups',
                                     at_startup=True)

    class ParentMethods:
        def summation(self, x, y):
            r"""
            Return the sum of ``x`` and ``y``.

            The binary addition operator of this additive magma.

            INPUT:

             - ``x``, ``y`` -- elements of this additive magma

            EXAMPLES::

                sage: S = CommutativeAdditiveSemigroups().example()
                sage: (a,b,c,d) = S.additive_semigroup_generators()
                sage: S.summation(a, b)
                a + b

            A parent in ``AdditiveMagmas()`` must
            either implement :meth:`.summation` in the parent class or
            ``_add_`` in the element class. By default, the addition
            method on elements ``x._add_(y)`` calls
            ``S.summation(x,y)``, and reciprocally.

            As a bonus effect, ``S.summation`` by itself models the
            binary function from ``S`` to ``S``::

                sage: bin = S.summation
                sage: bin(a,b)
                a + b

            Here, ``S.summation`` is just a bound method. Whenever
            possible, it is recommended to enrich ``S.summation`` with
            extra mathematical structure. Lazy attributes can come
            handy for this.

            .. TODO:: Add an example.
            """
            return x + y

        summation_from_element_class_add = summation

        def __init_extra__(self):
            """
            TESTS::

                sage: S = CommutativeAdditiveSemigroups().example()
                sage: (a,b,c,d) = S.additive_semigroup_generators()
                sage: a + b # indirect doctest
                a + b
                sage: a.__class__._add_ == a.__class__._add_parent
                True
            """
            # This should instead register the summation to the coercion model
            # But this is not yet implemented in the coercion model
            if (self.summation != self.summation_from_element_class_add
                ) and hasattr(self, "element_class") and hasattr(
                    self.element_class, "_add_parent"):
                self.element_class._add_ = self.element_class._add_parent

        def addition_table(self, names='letters', elements=None):
            r"""
            Return a table describing the addition operation.

            .. NOTE::

                The order of the elements in the row and column
                headings is equal to the order given by the table's
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`
                method.  The association can also be retrieved with the
                :meth:`~sage.matrix.operation_table.OperationTable.translation`
                method.

            INPUT:

            - ``names`` -- the type of names used:

              * ``'letters'`` - lowercase ASCII letters are used
                for a base 26 representation of the elements'
                positions in the list given by
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`,
                padded to a common width with leading 'a's.
              * ``'digits'`` - base 10 representation of the
                elements' positions in the list given by
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`,
                padded to a common width with leading zeros.
              * ``'elements'`` - the string representations
                of the elements themselves.
              * a list - a list of strings, where the length
                of the list equals the number of elements.

            - ``elements`` -- (default: ``None``)  A list of
              elements of the additive magma, in forms that
              can be coerced into the structure, eg. their
              string representations. This may be used to
              impose an alternate ordering on the elements,
              perhaps when this is used in the context of a
              particular structure. The default is to use
              whatever ordering the ``S.list`` method returns.
              Or the ``elements`` can be a subset which is
              closed under the operation. In particular,
              this can be used when the base set is infinite.

            OUTPUT:

            The addition table as an object of the class
            :class:`~sage.matrix.operation_table.OperationTable`
            which defines several methods for manipulating and
            displaying the table.  See the documentation there
            for full details to supplement the documentation
            here.

            EXAMPLES:

            All that is required is that an algebraic structure
            has an addition defined.The default is to represent
            elements as lowercase ASCII letters.  ::

                sage: R=IntegerModRing(5)
                sage: R.addition_table()
                +  a b c d e
                 +----------
                a| a b c d e
                b| b c d e a
                c| c d e a b
                d| d e a b c
                e| e a b c d

            The ``names`` argument allows displaying the elements in
            different ways.  Requesting ``elements`` will use the
            representation of the elements of the set.  Requesting
            ``digits`` will include leading zeros as padding.  ::

                sage: R=IntegerModRing(11)
                sage: P=R.addition_table(names='elements')
                sage: P
                 +   0  1  2  3  4  5  6  7  8  9 10
                  +---------------------------------
                 0|  0  1  2  3  4  5  6  7  8  9 10
                 1|  1  2  3  4  5  6  7  8  9 10  0
                 2|  2  3  4  5  6  7  8  9 10  0  1
                 3|  3  4  5  6  7  8  9 10  0  1  2
                 4|  4  5  6  7  8  9 10  0  1  2  3
                 5|  5  6  7  8  9 10  0  1  2  3  4
                 6|  6  7  8  9 10  0  1  2  3  4  5
                 7|  7  8  9 10  0  1  2  3  4  5  6
                 8|  8  9 10  0  1  2  3  4  5  6  7
                 9|  9 10  0  1  2  3  4  5  6  7  8
                10| 10  0  1  2  3  4  5  6  7  8  9

                sage: T=R.addition_table(names='digits')
                sage: T
                +  00 01 02 03 04 05 06 07 08 09 10
                  +---------------------------------
                00| 00 01 02 03 04 05 06 07 08 09 10
                01| 01 02 03 04 05 06 07 08 09 10 00
                02| 02 03 04 05 06 07 08 09 10 00 01
                03| 03 04 05 06 07 08 09 10 00 01 02
                04| 04 05 06 07 08 09 10 00 01 02 03
                05| 05 06 07 08 09 10 00 01 02 03 04
                06| 06 07 08 09 10 00 01 02 03 04 05
                07| 07 08 09 10 00 01 02 03 04 05 06
                08| 08 09 10 00 01 02 03 04 05 06 07
                09| 09 10 00 01 02 03 04 05 06 07 08
                10| 10 00 01 02 03 04 05 06 07 08 09

            Specifying the elements in an alternative order can provide
            more insight into how the operation behaves.  ::

                sage: S=IntegerModRing(7)
                sage: elts = [0, 3, 6, 2, 5, 1, 4]
                sage: S.addition_table(elements=elts)
                +  a b c d e f g
                 +--------------
                a| a b c d e f g
                b| b c d e f g a
                c| c d e f g a b
                d| d e f g a b c
                e| e f g a b c d
                f| f g a b c d e
                g| g a b c d e f

            The ``elements`` argument can be used to provide
            a subset of the elements of the structure.  The subset
            must be closed under the operation.  Elements need only
            be in a form that can be coerced into the set.  The
            ``names`` argument can also be used to request that
            the elements be represented with their usual string
            representation.  ::

                sage: T=IntegerModRing(12)
                sage: elts=[0, 3, 6, 9]
                sage: T.addition_table(names='elements', elements=elts)
                +  0 3 6 9
                 +--------
                0| 0 3 6 9
                3| 3 6 9 0
                6| 6 9 0 3
                9| 9 0 3 6

            The table returned can be manipulated in various ways.  See
            the documentation for
            :class:`~sage.matrix.operation_table.OperationTable` for more
            comprehensive documentation. ::

                sage: R=IntegerModRing(3)
                sage: T=R.addition_table()
                sage: T.column_keys()
                (0, 1, 2)
                sage: sorted(T.translation().items())
                [('a', 0), ('b', 1), ('c', 2)]
                sage: T.change_names(['x', 'y', 'z'])
                sage: sorted(T.translation().items())
                [('x', 0), ('y', 1), ('z', 2)]
                sage: T
                +  x y z
                 +------
                x| x y z
                y| y z x
                z| z x y
            """
            from sage.matrix.operation_table import OperationTable
            import operator
            return OperationTable(self,
                                  operation=operator.add,
                                  names=names,
                                  elements=elements)

    class ElementMethods:
        @abstract_method(optional=True)
        def _add_(self, right):
            """
            Return the sum of ``self`` and ``right``.

            INPUT:

            - ``self``, ``right`` -- two elements with the same parent

            OUTPUT:

            - an element of the same parent

            EXAMPLES::

                sage: F = CommutativeAdditiveSemigroups().example()
                sage: (a,b,c,d) = F.additive_semigroup_generators()
                sage: a._add_(b)
                a + b
            """

        def _add_parent(self, other):
            r"""
            Return the sum of the two elements, calculated using
            the ``summation`` method of the parent.

            This is the default implementation of _add_ if
            ``summation`` is implemented in the parent.

            INPUT:

            - ``other`` -- an element of the parent of ``self``

            OUTPUT:

            - an element of the parent of ``self``

            EXAMPLES::

                sage: S = CommutativeAdditiveSemigroups().example()
                sage: (a,b,c,d) = S.additive_semigroup_generators()
                sage: a._add_parent(b)
                a + b
            """
            return self.parent().summation(self, other)

    class Homsets(HomsetsCategory):
        def extra_super_categories(self):
            """
            Implement the fact that a homset between two magmas is a magma.

            EXAMPLES::

                sage: AdditiveMagmas().Homsets().extra_super_categories()
                [Category of additive magmas]
                sage: AdditiveMagmas().Homsets().super_categories()
                [Category of additive magmas, Category of homsets]
            """
            return [AdditiveMagmas()]

    class CartesianProducts(CartesianProductsCategory):
        def extra_super_categories(self):
            """
            Implement the fact that a Cartesian product of additive magmas is
            an additive magma.

            EXAMPLES::

                sage: C = AdditiveMagmas().CartesianProducts()
                sage: C.extra_super_categories()
                [Category of additive magmas]
                sage: C.super_categories()
                [Category of additive magmas, Category of Cartesian products of sets]
                sage: C.axioms()
                frozenset()
            """
            return [AdditiveMagmas()]

        class ElementMethods:
            def _add_(self, right):
                r"""
                EXAMPLES::

                    sage: G5=GF(5); G8=GF(4,'x'); GG = G5.cartesian_product(G8)
                    sage: e = GG((G5(1),G8.primitive_element())); e
                    (1, x)
                    sage: e+e
                    (2, 0)
                    sage: e=groups.misc.AdditiveCyclic(8)
                    sage: x=e.cartesian_product(e)((e(1),e(2)))
                    sage: x
                    (1, 2)
                    sage: 4*x
                    (4, 0)
                """
                return self.parent()._cartesian_product_of_elements(
                    x + y for x, y in zip(self.cartesian_factors(),
                                          right.cartesian_factors()))

    class Algebras(AlgebrasCategory):
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: AdditiveMagmas().Algebras(QQ).extra_super_categories()
                [Category of magmatic algebras with basis over Rational Field]

                sage: AdditiveMagmas().Algebras(QQ).super_categories()
                [Category of magmatic algebras with basis over Rational Field, Category of set algebras over Rational Field]
            """
            from sage.categories.magmatic_algebras import MagmaticAlgebras
            return [MagmaticAlgebras(self.base_ring()).WithBasis()]

        class ParentMethods:
            @cached_method
            def algebra_generators(self):
                r"""
                The generators of this algebra, as per
                :meth:`MagmaticAlgebras.ParentMethods.algebra_generators()
                <.magmatic_algebras.MagmaticAlgebras.ParentMethods.algebra_generators>`.

                They correspond to the generators of the additive semigroup.

                EXAMPLES::

                    sage: S = CommutativeAdditiveSemigroups().example(); S
                    An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd')
                    sage: A = S.algebra(QQ)
                    sage: A.algebra_generators()
                    Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]}
                """
                return self.basis().keys().additive_semigroup_generators().map(
                    self.monomial)

            def product_on_basis(self, g1, g2):
                r"""
                Product, on basis elements, as per
                :meth:`MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis()
                <.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis>`.

                The product of two basis elements is induced by the
                addition of the corresponding elements of the group.

                EXAMPLES::

                    sage: S = CommutativeAdditiveSemigroups().example(); S
                    An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd')
                    sage: A = S.algebra(QQ)
                    sage: a,b,c,d = A.algebra_generators()
                    sage: a * b + b * d * c
                    B[b + c + d] + B[a + b]
                """
                return self.monomial(g1 + g2)

    class AdditiveCommutative(CategoryWithAxiom):
        class CartesianProducts(CartesianProductsCategory):
            def extra_super_categories(self):
                """
                Implement the fact that a Cartesian product of commutative
                additive magmas is a commutative additive magma.

                EXAMPLES::

                    sage: C = AdditiveMagmas().AdditiveCommutative().CartesianProducts()
                    sage: C.extra_super_categories()
                    [Category of additive commutative additive magmas]
                    sage: C.axioms()
                    frozenset({'AdditiveCommutative'})
                """
                return [AdditiveMagmas().AdditiveCommutative()]

        class Algebras(AlgebrasCategory):
            def extra_super_categories(self):
                """
                Implement the fact that the algebra of a commutative additive
                magmas is commutative.

                EXAMPLES::

                    sage: AdditiveMagmas().AdditiveCommutative().Algebras(QQ).extra_super_categories()
                    [Category of commutative magmas]

                    sage: AdditiveMagmas().AdditiveCommutative().Algebras(QQ).super_categories()
                    [Category of additive magma algebras over Rational Field,
                     Category of commutative magmas]
                """
                from sage.categories.magmas import Magmas
                return [Magmas().Commutative()]

    class AdditiveUnital(CategoryWithAxiom):
        def additional_structure(self):
            r"""
            Return whether ``self`` is a structure category.

            .. SEEALSO:: :meth:`Category.additional_structure`

            The category of unital additive magmas defines the zero as
            additional structure, and this zero shall be preserved by
            morphisms.

            EXAMPLES::

                sage: AdditiveMagmas().AdditiveUnital().additional_structure()
                Category of additive unital additive magmas
            """
            return self

        class SubcategoryMethods:
            @cached_method
            def AdditiveInverse(self):
                r"""
                Return the full subcategory of the additive inverse objects
                of ``self``.

                An inverse :class:`additive magma <AdditiveMagmas>` is
                a :class:`unital additive magma <AdditiveMagmas.Unital>`
                such that every element admits both an additive
                inverse on the left and on the right. Such an additive
                magma is also called an *additive loop*.

                .. SEEALSO::

                    :wikipedia:`Inverse_element`, :wikipedia:`Quasigroup`

                EXAMPLES::

                    sage: AdditiveMagmas().AdditiveUnital().AdditiveInverse()
                    Category of additive inverse additive unital additive magmas
                    sage: from sage.categories.additive_monoids import AdditiveMonoids
                    sage: AdditiveMonoids().AdditiveInverse()
                    Category of additive groups

                TESTS::

                    sage: TestSuite(AdditiveMagmas().AdditiveUnital().AdditiveInverse()).run()
                    sage: CommutativeAdditiveMonoids().AdditiveInverse.__module__
                    'sage.categories.additive_magmas'
                """
                return self._with_axiom("AdditiveInverse")

        class ParentMethods:
            def _test_zero(self, **options):
                r"""
                Test that ``self.zero()`` is an element of self and
                is neutral for the addition.

                INPUT:

                - ``options`` -- any keyword arguments accepted
                  by :meth:`_tester`

                EXAMPLES:

                By default, this method tests only the elements returned by
                ``self.some_elements()``::

                    sage: S = CommutativeAdditiveMonoids().example()
                    sage: S._test_zero()

                However, the elements tested can be customized with the
                ``elements`` keyword argument::

                    sage: (a,b,c,d) = S.additive_semigroup_generators()
                    sage: S._test_zero(elements = (a, a+c))

                See the documentation for :class:`TestSuite` for
                more information.
                """
                tester = self._tester(**options)
                zero = self.zero()
                # TODO: also call is_zero once it will work
                tester.assertTrue(self.is_parent_of(zero))
                for x in tester.some_elements():
                    tester.assertTrue(x + zero == x)
                # Check that zero is immutable if it looks like we can:
                if hasattr(zero, "is_immutable"):
                    tester.assertEqual(zero.is_immutable(), True)
                if hasattr(zero, "is_mutable"):
                    tester.assertEqual(zero.is_mutable(), False)
                # Check that bool behave consistently on zero
                tester.assertFalse(bool(self.zero()))

            @cached_method
            def zero(self):
                """
                Return the zero of this additive magma, that is the unique
                neutral element for `+`.

                The default implementation is to coerce ``0`` into ``self``.

                It is recommended to override this method because the
                coercion from the integers:

                - is not always meaningful (except for `0`), and
                - often uses ``self.zero()`` otherwise.

                EXAMPLES::

                    sage: S = CommutativeAdditiveMonoids().example()
                    sage: S.zero()
                    0
                """
                # TODO: add a test that actually exercise this default implementation
                return self(0)

            def is_empty(self):
                r"""
                Return whether this set is empty.

                Since this set is an additive magma it has a zero element and
                hence is not empty. This method thus always returns ``False``.

                EXAMPLES::

                    sage: A = AdditiveAbelianGroup([3,3])
                    sage: A in AdditiveMagmas()
                    True
                    sage: A.is_empty()
                    False

                    sage: B = CommutativeAdditiveMonoids().example()
                    sage: B.is_empty()
                    False

                TESTS:

                We check that the method `is_empty` is inherited from this
                category in both examples above::

                    sage: A.is_empty.__module__
                    'sage.categories.additive_magmas'
                    sage: B.is_empty.__module__
                    'sage.categories.additive_magmas'
                """
                return False

        class ElementMethods:
            # TODO: merge with the implementation in Element which currently
            # overrides this one, and further requires self.parent()(0) to work.
            #
            # def is_zero(self):
            #     """
            #     Returns whether self is the zero of the magma
            #
            #     The default implementation, is to compare with ``self.zero()``.
            #
            #     TESTS::
            #
            #         sage: S = CommutativeAdditiveMonoids().example()
            #         sage: S.zero().is_zero()
            #         True
            #         sage: S("aa").is_zero()
            #         False
            #     """
            #     return self == self.parent().zero()

            @abstract_method
            def __bool__(self):
                """
                Return whether ``self`` is not zero.

                All parents in the category ``CommutativeAdditiveMonoids()``
                should implement this method.

                .. note:: This is currently not useful because this method is
                   overridden by ``Element``.

                TESTS::

                    sage: S = CommutativeAdditiveMonoids().example()
                    sage: bool(S.zero())
                    False
                    sage: bool(S.an_element())
                    True
                 """

            if six.PY2:
                __nonzero__ = __bool__
                del __bool__

            def _test_nonzero_equal(self, **options):
                r"""
                Test that ``.__bool__()`` behave consistently
                with `` == 0``.

                TESTS::

                    sage: S = CommutativeAdditiveMonoids().example()
                    sage: S.zero()._test_nonzero_equal()
                    sage: S.an_element()._test_nonzero_equal()
                """
                tester = self._tester(**options)
                tester.assertEqual(bool(self), self != self.parent().zero())
                tester.assertEqual(not self, self == self.parent().zero())

            def _sub_(left, right):
                r"""
                Default implementation of difference.

                EXAMPLES::

                    sage: F = CombinatorialFreeModule(QQ, ['a','b'])
                    sage: a,b = F.basis()
                    sage: a - b
                    B['a'] - B['b']

                TESTS:

                Check that :trac:`18275` is fixed::

                    sage: C = GF(5).cartesian_product(GF(5))
                    sage: C.one() - C.one()
                    (0, 0)
                """
                return left + (-right)

            def __neg__(self):
                """
                Return the negation of ``self``, if it exists.

                This top-level implementation delegates the job to
                ``_neg_``, for those additive unital magmas which may
                choose to implement it instead of ``__neg__`` for
                consistency.

                EXAMPLES::

                    sage: F = CombinatorialFreeModule(QQ, ['a','b'])
                    sage: a,b = F.basis()
                    sage: - b
                    -B['b']

                TESTS::

                    sage: F = CombinatorialFreeModule(ZZ, ['a','b'])
                    sage: a,b = F.gens()
                    sage: FF = cartesian_product((F,F))
                    sage: x = cartesian_product([a,2*a-3*b]) ; x
                    B[(0, 'a')] + 2*B[(1, 'a')] - 3*B[(1, 'b')]
                    sage: x.parent() is FF
                    True
                    sage: -x
                    -B[(0, 'a')] - 2*B[(1, 'a')] + 3*B[(1, 'b')]
                """
                return self._neg_()

        class Homsets(HomsetsCategory):
            def extra_super_categories(self):
                """
                Implement the fact that a homset between two unital additive
                magmas is a unital additive magma.

                EXAMPLES::

                    sage: AdditiveMagmas().AdditiveUnital().Homsets().extra_super_categories()
                    [Category of additive unital additive magmas]
                    sage: AdditiveMagmas().AdditiveUnital().Homsets().super_categories()
                    [Category of additive unital additive magmas, Category of homsets]
                """
                return [AdditiveMagmas().AdditiveUnital()]

            class ParentMethods:
                @cached_method
                def zero(self):
                    """
                    EXAMPLES::

                        sage: R = QQ['x']
                        sage: H = Hom(ZZ, R, AdditiveMagmas().AdditiveUnital())
                        sage: f = H.zero()
                        sage: f
                        Generic morphism:
                          From: Integer Ring
                          To:   Univariate Polynomial Ring in x over Rational Field
                        sage: f(3)
                        0
                        sage: f(3) is R.zero()
                        True

                    TESTS:

                        sage: TestSuite(f).run()
                    """
                    from sage.misc.constant_function import ConstantFunction
                    return self(ConstantFunction(self.codomain().zero()))

        class AdditiveInverse(CategoryWithAxiom):
            class CartesianProducts(CartesianProductsCategory):
                def extra_super_categories(self):
                    """
                    Implement the fact that a Cartesian product of additive magmas
                    with inverses is an additive magma with inverse.

                    EXAMPLES::

                        sage: C = AdditiveMagmas().AdditiveUnital().AdditiveInverse().CartesianProducts()
                        sage: C.extra_super_categories()
                        [Category of additive inverse additive unital additive magmas]
                        sage: sorted(C.axioms())
                        ['AdditiveInverse', 'AdditiveUnital']
                    """
                    return [
                        AdditiveMagmas().AdditiveUnital().AdditiveInverse()
                    ]

                class ElementMethods:
                    def _neg_(self):
                        """
                        Return the negation of ``self``.

                        EXAMPLES::

                           sage: x = cartesian_product((GF(7)(2),17)) ; x
                           (2, 17)
                           sage: -x
                           (5, -17)

                        TESTS::

                           sage: x.parent() in AdditiveMagmas().AdditiveUnital().AdditiveInverse().CartesianProducts()
                           True
                        """
                        return self.parent()._cartesian_product_of_elements(
                            [-x for x in self.cartesian_factors()])

        class CartesianProducts(CartesianProductsCategory):
            def extra_super_categories(self):
                """
                Implement the fact that a Cartesian product of unital additive
                magmas is a unital additive magma.

                EXAMPLES::

                    sage: C = AdditiveMagmas().AdditiveUnital().CartesianProducts()
                    sage: C.extra_super_categories()
                    [Category of additive unital additive magmas]
                    sage: C.axioms()
                    frozenset({'AdditiveUnital'})
                """
                return [AdditiveMagmas().AdditiveUnital()]

            class ParentMethods:
                def zero(self):
                    r"""
                    Returns the zero of this group

                    EXAMPLES::

                        sage: GF(8,'x').cartesian_product(GF(5)).zero()
                        (0, 0)
                    """
                    return self._cartesian_product_of_elements(
                        _.zero() for _ in self.cartesian_factors())

        class Algebras(AlgebrasCategory):
            def extra_super_categories(self):
                """
                EXAMPLES::

                    sage: C = AdditiveMagmas().AdditiveUnital().Algebras(QQ)
                    sage: C.extra_super_categories()
                    [Category of unital magmas]

                    sage: C.super_categories()
                    [Category of unital algebras with basis over Rational Field, Category of additive magma algebras over Rational Field]
                """
                from sage.categories.magmas import Magmas
                return [Magmas().Unital()]

            class ParentMethods:
                @cached_method
                def one_basis(self):
                    """
                    Return the zero of this additive magma, which index the
                    one of this algebra, as per
                    :meth:`AlgebrasWithBasis.ParentMethods.one_basis()
                    <sage.categories.algebras_with_basis.AlgebrasWithBasis.ParentMethods.one_basis>`.

                    EXAMPLES::

                        sage: S = CommutativeAdditiveMonoids().example(); S
                        An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd')
                        sage: A = S.algebra(ZZ)
                        sage: A.one_basis()
                        0
                        sage: A.one()
                        B[0]
                        sage: A(3)
                        3*B[0]
                    """
                    return self.basis().keys().zero()

        class WithRealizations(WithRealizationsCategory):
            class ParentMethods:
                def zero(self):
                    r"""
                    Return the zero of this unital additive magma.

                    This default implementation returns the zero of the
                    realization of ``self`` given by
                    :meth:`~Sets.WithRealizations.ParentMethods.a_realization`.

                    EXAMPLES::

                        sage: A = Sets().WithRealizations().example(); A
                        The subset algebra of {1, 2, 3} over Rational Field
                        sage: A.zero.__module__
                        'sage.categories.additive_magmas'
                        sage: A.zero()
                        0

                    TESTS::

                        sage: A.zero() is A.a_realization().zero()
                        True
                        sage: A._test_zero()
                    """
                    return self.a_realization().zero()
Ejemplo n.º 15
0
class Magmas(Category_singleton):
    """
    The category of (multiplicative) magmas.

    A magma is a set with a binary operation `*`.

    EXAMPLES::

        sage: Magmas()
        Category of magmas
        sage: Magmas().super_categories()
        [Category of sets]
        sage: Magmas().all_super_categories()
        [Category of magmas, Category of sets,
         Category of sets with partial maps, Category of objects]

    The following axioms are defined by this category::

        sage: Magmas().Associative()
        Category of semigroups
        sage: Magmas().Unital()
        Category of unital magmas
        sage: Magmas().Commutative()
        Category of commutative magmas
        sage: Magmas().Unital().Inverse()
        Category of inverse unital magmas
        sage: Magmas().Associative()
        Category of semigroups
        sage: Magmas().Associative().Unital()
        Category of monoids
        sage: Magmas().Associative().Unital().Inverse()
        Category of groups

    TESTS::

        sage: C = Magmas()
        sage: TestSuite(C).run()
    """
    def super_categories(self):
        """
        EXAMPLES::

            sage: Magmas().super_categories()
            [Category of sets]
        """
        return [Sets()]

    class SubcategoryMethods:

        @cached_method
        def Associative(self):
            """
            Return the full subcategory of the associative objects
            of ``self``.

            A (multiplicative) :class:`magma Magmas` `M` is
            *associative* if, for all `x,y,z\in M`,

            .. MATH:: x * (y * z) = (x * y) * z

            .. SEEALSO:: :wikipedia:`Associative_property`

            EXAMPLES::

                sage: Magmas().Associative()
                Category of semigroups

            TESTS::

                sage: TestSuite(Magmas().Associative()).run()
                sage: Rings().Associative.__module__
                'sage.categories.magmas'
            """
            return self._with_axiom('Associative')

        @cached_method
        def Commutative(self):
            """
            Return the full subcategory of the commutative objects
            of ``self``.

            A (multiplicative) :class:`magma Magmas` `M` is
            *commutative* if, for all `x,y\in M`,

            .. MATH:: x * y = y * x

            .. SEEALSO:: :wikipedia:`Commutative_property`

            EXAMPLES::

                sage: Magmas().Commutative()
                Category of commutative magmas
                sage: Monoids().Commutative()
                Category of commutative monoids

            TESTS::

                sage: TestSuite(Magmas().Commutative()).run()
                sage: Rings().Commutative.__module__
                'sage.categories.magmas'
            """
            return self._with_axiom('Commutative')

        @cached_method
        def Unital(self):
            r"""
            Return the subcategory of the unital objects of ``self``.

            A (multiplicative) :class:`magma Magmas` `M` is *unital*
            if it admits an element `1`, called *unit*, such that for
            all `x\in M`,

            .. MATH:: 1 * x = x * 1 = x

            This element is necessarily unique, and should be provided
            as ``M.one()``.

            .. SEEALSO:: :wikipedia:`Unital_magma#unital`

            EXAMPLES::

                sage: Magmas().Unital()
                Category of unital magmas
                sage: Semigroups().Unital()
                Category of monoids
                sage: Monoids().Unital()
                Category of monoids
                sage: from sage.categories.associative_algebras import AssociativeAlgebras
                sage: AssociativeAlgebras(QQ).Unital()
                Category of algebras over Rational Field

            TESTS::

                sage: TestSuite(Magmas().Unital()).run()
                sage: Semigroups().Unital.__module__
                'sage.categories.magmas'
            """
            return self._with_axiom("Unital")

        @cached_method
        def FinitelyGeneratedAsMagma(self):
            r"""
            Return the subcategory of the objects of ``self`` that are
            endowed with a distinguished finite set of
            (multiplicative) magma generators.

            A set `S` of elements of a multiplicative magma form a
            *set of generators* if any element of the magma can be
            expressed recursively from elements of `S` and products
            thereof.

            It is not imposed that morphisms shall preserve the
            distinguished set of generators; hence this is a full
            subcategory.

            .. SEEALSO:: :wikipedia:`Unital_magma#unital`

            EXAMPLES::

                sage: Magmas().FinitelyGeneratedAsMagma()
                Category of finitely generated magmas

            Being finitely generated does depend on the structure: for
            a ring, being finitely generated as a magma, as an
            additive magma, or as a ring are different concepts. Hence
            the name of this axiom is explicit::

                sage: Rings().FinitelyGeneratedAsMagma()
                Category of finitely generated as magma rings

            On the other hand, it does not depend on the
            multiplicative structure: for example a group is finitely
            generated if and only if it is finitely generated as a
            magma. A short hand is provided when there is no
            ambiguity, and the output tries to reflect that::

                sage: Semigroups().FinitelyGenerated()
                Category of finitely generated semigroups
                sage: Groups().FinitelyGenerated()
                Category of finitely generated groups

                sage: Semigroups().FinitelyGenerated().axioms()
                frozenset({'Associative', 'FinitelyGeneratedAsMagma'})

            Note that the set of generators may depend on the actual
            category; for example, in a group, one can often use less
            generators since it is allowed to take inverses.

            TESTS::

                sage: TestSuite(Magmas().FinitelyGeneratedAsMagma()).run()
                sage: Semigroups().FinitelyGeneratedAsMagma.__module__
                'sage.categories.magmas'
            """
            return self._with_axiom("FinitelyGeneratedAsMagma")

        @cached_method
        def FinitelyGenerated(self):
            r"""
            Return the subcategory of the objects of ``self`` that are
            endowed with a distinguished finite set of
            (multiplicative) magma generators.

            EXAMPLES:

            This is a shorthand for :meth:`FinitelyGeneratedAsMagma`,
            which see::

                sage: Magmas().FinitelyGenerated()
                Category of finitely generated magmas
                sage: Semigroups().FinitelyGenerated()
                Category of finitely generated semigroups
                sage: Groups().FinitelyGenerated()
                Category of finitely generated groups

            An error is raised if this is ambiguous::

                sage: (Magmas() & AdditiveMagmas()).FinitelyGenerated()
                Traceback (most recent call last):
                ...
                ValueError: FinitelyGenerated is ambiguous for
                Join of Category of magmas and Category of additive magmas.
                Please use explicitly one of the FinitelyGeneratedAsXXX methods

            .. NOTE::

                Checking that there is no ambiguity currently assumes
                that all the other "finitely generated" axioms involve
                an additive structure. As of Sage 6.4, this is
                correct.

                The use of this shorthand should be reserved for casual
                interactive use or when there is no risk of ambiguity.
                """
            from sage.categories.additive_magmas import AdditiveMagmas
            if self.is_subcategory(AdditiveMagmas()):
                raise ValueError("FinitelyGenerated is ambiguous for {}.\nPlease use explicitly one of the FinitelyGeneratedAsXXX methods".format(self))
            return self.FinitelyGeneratedAsMagma()

        @cached_method
        def Distributive(self):
            """
            Return the full subcategory of the objects of ``self``
            where `*` is distributive on `+`.

            INPUT:

            - ``self`` -- a subcategory of :class:`Magmas`
              and :class:`AdditiveMagmas`

            Given that Sage does not yet know that the category
            :class:`MagmasAndAdditiveMagmas` is the intersection of
            the categories :class:`Magmas` and
            :class:`AdditiveMagmas`, the method
            :meth:`MagmasAndAdditiveMagmas.SubcategoryMethods.Distributive`
            is not available, as would be desirable, for this intersection.

            This method is a workaround. It checks that ``self`` is a
            subcategory of both :class:`Magmas` and
            :class:`AdditiveMagmas` and upgrades it to a subcategory
            of :class:`MagmasAndAdditiveMagmas` before applying the
            axiom. It complains overwise, since the ``Distributive``
            axiom does not make sense for a plain magma.

            EXAMPLES::

                sage: (Magmas() & AdditiveMagmas()).Distributive()
                Category of distributive magmas and additive magmas
                sage: (Monoids() & CommutativeAdditiveGroups()).Distributive()
                Category of rings

                sage: Magmas().Distributive()
                Traceback (most recent call last):
                ...
                ValueError: The distributive axiom only makes sense on a magma which is simultaneously an additive magma
                sage: Semigroups().Distributive()
                Traceback (most recent call last):
                ...
                ValueError: The distributive axiom only makes sense on a magma which is simultaneously an additive magma

            TESTS::

                sage: Semigroups().Distributive.__module__
                'sage.categories.magmas'
                sage: Rings().Distributive.__module__
                'sage.categories.magmas_and_additive_magmas'
            """
            from .additive_magmas import AdditiveMagmas
            if not self.is_subcategory(AdditiveMagmas()):
                raise ValueError("The distributive axiom only makes sense on a magma which is simultaneously an additive magma")
            from .magmas_and_additive_magmas import MagmasAndAdditiveMagmas
            return (self & MagmasAndAdditiveMagmas()).Distributive()

        def JTrivial(self):
            r"""
            Return the full subcategory of the `J`-trivial objects of ``self``.

            This axiom is in fact only meaningful for
            :class:`semigroups <Semigroups>`. This stub definition is
            here as a workaround for :trac:`20515`, in order to define
            the `J`-trivial axiom as the intersection of the `L` and
            `R`-trivial axioms.

            .. SEEALSO:: :meth:`Semigroups.SubcategoryMethods.JTrivial`

            TESTS::

                sage: Magmas().JTrivial()
                Category of j trivial magmas
                sage: (Semigroups().RTrivial() & Semigroups().LTrivial()) is Semigroups().JTrivial()
                True
            """
            return self._with_axiom('JTrivial')

    Associative = LazyImport('sage.categories.semigroups', 'Semigroups', at_startup=True)
    FinitelyGeneratedAsMagma = LazyImport('sage.categories.finitely_generated_magmas', 'FinitelyGeneratedMagmas')

    class JTrivial(CategoryWithAxiom):
        # Workaround for #20515; see also Magmas.SubcategoryMethods.JTrivial
        pass

    class Algebras(AlgebrasCategory):

        def extra_super_categories(self):
            """
            EXAMPLES:

                sage: Magmas().Commutative().Algebras(QQ).extra_super_categories()
                [Category of commutative magmas]

            This implements the fact that the algebra of a commutative
            magma is commutative::

                sage: Magmas().Commutative().Algebras(QQ).super_categories()
                [Category of magma algebras over Rational Field, Category of commutative magmas]

            In particular, commutative monoid algebras are
            commutative algebras::

                sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative())
                True
            """
            from sage.categories.magmatic_algebras import MagmaticAlgebras
            return [MagmaticAlgebras(self.base_ring())]

    class Commutative(CategoryWithAxiom):

        class ParentMethods:
            def is_commutative(self):
                """
                Return ``True``, since commutative magmas are commutative.

                EXAMPLES::

                    sage: Parent(QQ,category=CommutativeRings()).is_commutative()
                    True
                """
                return True

        class Algebras(AlgebrasCategory):

            def extra_super_categories(self):
                """
                EXAMPLES:

                    sage: Magmas().Commutative().Algebras(QQ).extra_super_categories()
                    [Category of commutative magmas]

                This implements the fact that the algebra of a commutative
                magma is commutative::

                    sage: Magmas().Commutative().Algebras(QQ).super_categories()
                    [Category of magma algebras over Rational Field,
                     Category of commutative magmas]

                In particular, commutative monoid algebras are
                commutative algebras::

                    sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative())
                    True
                """
                return [Magmas().Commutative()]

        class CartesianProducts(CartesianProductsCategory):
            def extra_super_categories(self):
                r"""
                Implement the fact that a Cartesian product of commutative
                additive magmas is still an commutative additive magmas.

                EXAMPLES::

                    sage: C = Magmas().Commutative().CartesianProducts()
                    sage: C.extra_super_categories()
                    [Category of commutative magmas]
                    sage: C.axioms()
                    frozenset({'Commutative'})
                """
                return [Magmas().Commutative()]

    class Unital(CategoryWithAxiom):

        def additional_structure(self):
            r"""
            Return ``self``.

            Indeed, the category of unital magmas defines an
            additional structure, namely the unit of the magma which
            shall be preserved by morphisms.

            .. SEEALSO:: :meth:`Category.additional_structure`

            EXAMPLES::

                sage: Magmas().Unital().additional_structure()
                Category of unital magmas
            """
            return self

        class ParentMethods:
            @cached_method
            def one(self):
                r"""
                Return the unit of the monoid, that is the unique neutral
                element for `*`.

                .. NOTE::

                   The default implementation is to coerce `1` into ``self``.
                   It is recommended to override this method because the
                   coercion from the integers:

                    - is not always meaningful (except for `1`);
                    - often uses ``self.one()``.

                EXAMPLES::

                    sage: M = Monoids().example(); M
                    An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd')
                    sage: M.one()
                    ''
                """
                return self(1)

            def _test_one(self, **options):
                r"""
                Test that ``self.one()`` is an element of ``self`` and is
                neutral for the operation ``*``.

                INPUT:

                - ``options`` -- any keyword arguments accepted by :meth:`_tester`

                EXAMPLES:

                By default, this method tests only the elements returned by
                ``self.some_elements()``::

                    sage: S = Monoids().example()
                    sage: S._test_one()

                However, the elements tested can be customized with the
                ``elements`` keyword argument::

                    sage: S._test_one(elements = (S('a'), S('b')))

                See the documentation for :class:`TestSuite` for more information.
                """
                tester = self._tester(**options)
                one = self.one()
                tester.assert_(self.is_parent_of(one))
                for x in tester.some_elements():
                    tester.assert_(x * one == x)
                    tester.assert_(one * x == x)
                # Check that one is immutable if it looks like we can test this
                if hasattr(one,"is_immutable"):
                    tester.assertEqual(one.is_immutable(),True)
                if hasattr(one,"is_mutable"):
                    tester.assertEqual(one.is_mutable(),False)

            def is_empty(self):
                r"""
                Return whether ``self`` is empty.

                Since this set is a unital magma it is not empty and this method
                always return ``False``.

                EXAMPLES::

                    sage: S = SymmetricGroup(2)
                    sage: S.is_empty()
                    False

                    sage: M = Monoids().example()
                    sage: M.is_empty()
                    False

                TESTS::

                    sage: S.is_empty.__module__
                    'sage.categories.magmas'
                    sage: M.is_empty.__module__
                    'sage.categories.magmas'
                """
                return False

        class ElementMethods:

            __truediv__ = sage.categories.coercion_methods.__truediv__
            __div__ = __truediv__ # For Python2/3 compatibility; see e.g. #18578

            def _div_(left, right):
                r"""
                Default implementation of division, multiplying (on the right) by the inverse.

                INPUT:

                - ``left``, ``right`` -- two elements of the same unital magma

                .. SEEALSO:: :meth:`__div__`

                EXAMPLES::

                    sage: G = FreeGroup(2)
                    sage: x0, x1 = G.group_generators()
                    sage: c1 = cartesian_product([x0, x1])
                    sage: c2 = cartesian_product([x1, x0])
                    sage: c1._div_(c2)
                    (x0*x1^-1, x1*x0^-1)

                With this implementation, division will fail as soon
                as ``right`` is not invertible, even if ``right``
                actually divides ``left``::

                    sage: x = cartesian_product([2, 1])
                    sage: y = cartesian_product([1, 1])
                    sage: x / y
                    (2, 1)
                    sage: x / x
                    Traceback (most recent call last):
                    ...
                    TypeError: no conversion of this rational to integer

                TESTS::

                    sage: c1._div_.__module__
                    'sage.categories.magmas'
                """
                return left._mul_(~right)

        class SubcategoryMethods:

            @cached_method
            def Inverse(self):
                r"""
                Return the full subcategory of the inverse objects of ``self``.

                An inverse :class:` (multiplicative) magma <Magmas>`
                is a :class:`unital magma <Magmas.Unital>` such that
                every element admits both an inverse on the left and
                on the right. Such a magma is also called a *loop*.

                .. SEEALSO::

                    :wikipedia:`Inverse_element`, :wikipedia:`Quasigroup`

                EXAMPLES::

                    sage: Magmas().Unital().Inverse()
                    Category of inverse unital magmas
                    sage: Monoids().Inverse()
                    Category of groups

                TESTS::

                    sage: TestSuite(Magmas().Unital().Inverse()).run()
                    sage: Algebras(QQ).Inverse.__module__
                    'sage.categories.magmas'
                """
                return self._with_axiom("Inverse")

        class Inverse(CategoryWithAxiom):
            class CartesianProducts(CartesianProductsCategory):
                def extra_super_categories(self):
                    """
                    Implement the fact that a Cartesian product of magmas with
                    inverses is a magma with inverse.

                    EXAMPLES::

                        sage: C = Magmas().Unital().Inverse().CartesianProducts()
                        sage: C.extra_super_categories();
                        [Category of inverse unital magmas]
                        sage: sorted(C.axioms())
                        ['Inverse', 'Unital']
                    """
                    return [Magmas().Unital().Inverse()]

        class CartesianProducts(CartesianProductsCategory):
            def extra_super_categories(self):
                """
                Implement the fact that a Cartesian product of unital magmas is
                a unital magma

                EXAMPLES::

                    sage: C = Magmas().Unital().CartesianProducts()
                    sage: C.extra_super_categories();
                    [Category of unital magmas]
                    sage: C.axioms()
                    frozenset({'Unital'})

                    sage: Monoids().CartesianProducts().is_subcategory(Monoids())
                    True
                """
                return [Magmas().Unital()]

            class ParentMethods:

                @cached_method
                def one(self):
                    """
                    Return the unit of this Cartesian product.

                    It is built from the units for the Cartesian factors of ``self``.

                    EXAMPLES::

                        sage: cartesian_product([QQ, ZZ, RR]).one()
                        (1, 1, 1.00000000000000)
                    """
                    return self._cartesian_product_of_elements(
                        _.one() for _ in self.cartesian_factors())

            class ElementMethods:
                def __invert__(self):
                    r"""
                    Return the inverse of ``self``, if it exists.

                    The inverse is computed by inverting each
                    Cartesian factor and attempting to convert the
                    result back to the original parent.

                    For example, if one of the Cartesian factor is an
                    element ``x`` of `\ZZ`, the result of ``~x`` is in
                    `\QQ`. So we need to convert it back to `\ZZ`. As
                    a side effect, this checks that ``x`` is indeed
                    invertible in `\ZZ`.

                    If needed an optimized version without this
                    conversion could be implemented in
                    :class:`Magmas.Unital.Inverse.ElementMethods`.

                    EXAMPLES::

                        sage: C = cartesian_product([QQ, ZZ, RR, GF(5)])
                        sage: c = C([2,-1,2,2]); c
                        (2, -1, 2.00000000000000, 2)
                        sage: ~c
                        (1/2, -1, 0.500000000000000, 3)

                    This fails as soon as one of the entries is not
                    invertible::

                        sage: ~C([0,2,2,2])
                        Traceback (most recent call last):
                        ...
                        ZeroDivisionError: rational division by zero

                        sage: ~C([2,2,2,2])
                        Traceback (most recent call last):
                        ...
                        TypeError: no conversion of this rational to integer
                    """
                    # variant without coercion:
                    # return self.parent()._cartesian_product_of_elements(
                    return self.parent()(
                        ~x for x in self.cartesian_factors())

        class Algebras(AlgebrasCategory):

            def extra_super_categories(self):
                """
                EXAMPLES:

                    sage: Magmas().Commutative().Algebras(QQ).extra_super_categories()
                    [Category of commutative magmas]

                This implements the fact that the algebra of a
                commutative magma is commutative::

                    sage: Magmas().Commutative().Algebras(QQ).super_categories()
                    [Category of magma algebras over Rational Field,
                     Category of commutative magmas]

                In particular, commutative monoid algebras are
                commutative algebras::

                    sage: Monoids().Commutative().Algebras(QQ).is_subcategory(Algebras(QQ).Commutative())
                    True
                """
                return [Magmas().Unital()]

        class Realizations(RealizationsCategory):

            class ParentMethods:

                @cached_method
                def one(self):
                    r"""
                    Return the unit element of ``self``.

                        sage: from sage.combinat.root_system.extended_affine_weyl_group import ExtendedAffineWeylGroup
                        sage: PvW0 = ExtendedAffineWeylGroup(['A',2,1]).PvW0()
                        sage: PvW0 in Magmas().Unital().Realizations()
                        True
                        sage: PvW0.one()
                        1
                    """
                    return(self(self.realization_of().a_realization().one()))

    class ParentMethods:

        def product(self, x, y):
            """
            The binary multiplication of the magma.

            INPUT:

            - ``x``, ``y`` -- elements of this magma

            OUTPUT:

            - an element of the magma (the product of ``x`` and ``y``)

            EXAMPLES::

                sage: S = Semigroups().example("free")
                sage: x = S('a'); y = S('b')
                sage: S.product(x, y)
                'ab'

            A parent in ``Magmas()`` must either implement
            :meth:`.product` in the parent class or ``_mul_`` in the
            element class. By default, the addition method on elements
            ``x._mul_(y)`` calls ``S.product(x,y)``, and reciprocally.

            As a bonus, ``S.product`` models the binary function from
            ``S`` to ``S``::

                sage: bin = S.product
                sage: bin(x,y)
                'ab'

            Currently, ``S.product`` is just a bound method::

                sage: bin
                <bound method FreeSemigroup_with_category.product of An example of a semigroup: the free semigroup generated by ('a', 'b', 'c', 'd')>

            When Sage will support multivariate morphisms, it will be
            possible, and in fact recommended, to enrich ``S.product``
            with extra mathematical structure. This will typically be
            implemented using lazy attributes.::

                sage: bin                 # todo: not implemented
                Generic binary morphism:
                From: (S x S)
                To:   S
            """
            return x._mul_(y)

        product_from_element_class_mul = product

        def __init_extra__(self):
            """
                sage: S = Semigroups().example("free")
                sage: S('a') * S('b') # indirect doctest
                'ab'
                sage: S('a').__class__._mul_ == S('a').__class__._mul_parent
                True
            """
            # This should instead register the multiplication to the coercion model
            # But this is not yet implemented in the coercion model
            #
            # Trac ticket #11900: The following used to test whether
            # self.product != self.product_from_element_class_mul. But
            # that is, of course, a bug. Namely otherwise, if the parent
            # has an optimized `product` then its elements will *always* use
            # a slow generic `_mul_`.
            #
            # So, in addition, it should be tested whether the element class exists
            # *and* has a custom _mul_, because in this case it must not be overridden.
            if (self.product.__func__ == self.product_from_element_class_mul.__func__):
                return
            if not (hasattr(self, "element_class") and hasattr(self.element_class, "_mul_parent")):
                return
            E = self.element_class
            if hasattr(E._mul_,'__func__'):
                try:
                    el_class_mul = self.category().element_class._mul_.__func__
                except AttributeError: # abstract method
                    return
                if E._mul_.__func__ is el_class_mul:
                    # self.product is custom, thus, we rely on it
                    E._mul_ = E._mul_parent
            else: # E._mul_ has so far been abstract
                E._mul_ = E._mul_parent

        def multiplication_table(self, names='letters', elements=None):
            r"""
            Returns a table describing the multiplication operation.

            .. note:: The order of the elements in the row and column
              headings is equal to the order given by the table's
              :meth:`~sage.matrix.operation_table.OperationTable.list`
              method.  The association can also be retrieved with the
              :meth:`~sage.matrix.operation_table.OperationTable.dict`
              method.

            INPUT:

            - ``names`` - the type of names used

              * ``'letters'`` - lowercase ASCII letters are used
                for a base 26 representation of the elements'
                positions in the list given by
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`,
                padded to a common width with leading 'a's.
              * ``'digits'`` - base 10 representation of the
                elements' positions in the list given by
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`,
                padded to a common width with leading zeros.
              * ``'elements'`` - the string representations
                of the elements themselves.
              * a list - a list of strings, where the length
                of the list equals the number of elements.
            - ``elements`` - default = ``None``.  A list of
              elements of the magma, in forms that can be
              coerced into the structure, eg. their string
              representations. This may be used to impose an
              alternate ordering on the elements, perhaps when
              this is used in the context of a particular structure.
              The default is to use whatever ordering the ``S.list``
              method returns. Or the ``elements`` can be a subset
              which is closed under the operation. In particular,
              this can be used when the base set is infinite.

            OUTPUT:
            The multiplication table as an object of the class
            :class:`~sage.matrix.operation_table.OperationTable`
            which defines several methods for manipulating and
            displaying the table.  See the documentation there
            for full details to supplement the documentation
            here.

            EXAMPLES:

            The default is to represent elements as lowercase
            ASCII letters.  ::

                sage: G=CyclicPermutationGroup(5)
                sage: G.multiplication_table()
                *  a b c d e
                 +----------
                a| a b c d e
                b| b c d e a
                c| c d e a b
                d| d e a b c
                e| e a b c d

            All that is required is that an algebraic structure
            has a multiplication defined.  A
            :class:`~sage.categories.examples.finite_semigroups.LeftRegularBand`
            is an example of a finite semigroup.  The ``names`` argument allows
            displaying the elements in different ways.  ::

                sage: from sage.categories.examples.finite_semigroups import LeftRegularBand
                sage: L=LeftRegularBand(('a','b'))
                sage: T=L.multiplication_table(names='digits')
                sage: T.column_keys()
                ('a', 'b', 'ab', 'ba')
                sage: T
                *  0 1 2 3
                 +--------
                0| 0 2 2 2
                1| 3 1 3 3
                2| 2 2 2 2
                3| 3 3 3 3

            Specifying the elements in an alternative order can provide
            more insight into how the operation behaves.  ::

                sage: L=LeftRegularBand(('a','b','c'))
                sage: elts = sorted(L.list())
                sage: L.multiplication_table(elements=elts)
                *  a b c d e f g h i j k l m n o
                 +------------------------------
                a| a b c d e b b c c c d d e e e
                b| b b c c c b b c c c c c c c c
                c| c c c c c c c c c c c c c c c
                d| d e e d e e e e e e d d e e e
                e| e e e e e e e e e e e e e e e
                f| g g h h h f g h i j i j j i j
                g| g g h h h g g h h h h h h h h
                h| h h h h h h h h h h h h h h h
                i| j j j j j i j j i j i j j i j
                j| j j j j j j j j j j j j j j j
                k| l m m l m n o o n o k l m n o
                l| l m m l m m m m m m l l m m m
                m| m m m m m m m m m m m m m m m
                n| o o o o o n o o n o n o o n o
                o| o o o o o o o o o o o o o o o

            The ``elements`` argument can be used to provide
            a subset of the elements of the structure.  The subset
            must be closed under the operation.  Elements need only
            be in a form that can be coerced into the set.  The
            ``names`` argument can also be used to request that
            the elements be represented with their usual string
            representation.  ::

                sage: L=LeftRegularBand(('a','b','c'))
                sage: elts=['a', 'c', 'ac', 'ca']
                sage: L.multiplication_table(names='elements', elements=elts)
                   *   'a'  'c' 'ac' 'ca'
                    +--------------------
                 'a'|  'a' 'ac' 'ac' 'ac'
                 'c'| 'ca'  'c' 'ca' 'ca'
                'ac'| 'ac' 'ac' 'ac' 'ac'
                'ca'| 'ca' 'ca' 'ca' 'ca'

            The table returned can be manipulated in various ways.  See
            the documentation for
            :class:`~sage.matrix.operation_table.OperationTable` for more
            comprehensive documentation. ::

                sage: G=AlternatingGroup(3)
                sage: T=G.multiplication_table()
                sage: T.column_keys()
                ((), (1,2,3), (1,3,2))
                sage: sorted(T.translation().items())
                [('a', ()), ('b', (1,2,3)), ('c', (1,3,2))]
                sage: T.change_names(['x', 'y', 'z'])
                sage: sorted(T.translation().items())
                [('x', ()), ('y', (1,2,3)), ('z', (1,3,2))]
                sage: T
                *  x y z
                 +------
                x| x y z
                y| y z x
                z| z x y
            """
            from sage.matrix.operation_table import OperationTable
            import operator
            return OperationTable(self, operation=operator.mul, names=names, elements=elements)

    class ElementMethods:

        __mul__ = sage.categories.coercion_methods.__mul__

        @abstract_method(optional = True)
        def _mul_(self, right):
            """
            Product of two elements

            INPUT:

            - ``self``, ``right`` -- two elements with the same parent

            OUTPUT:

            - an element of the same parent

            EXAMPLES::

                sage: S = Semigroups().example("free")
                sage: x = S('a'); y = S('b')
                sage: x._mul_(y)
                'ab'
            """

        _mul_parent = sage.categories.coercion_methods._mul_parent

        def is_idempotent(self):
            r"""
            Test whether ``self`` is idempotent.

            EXAMPLES::

                sage: S = Semigroups().example("free"); S
                An example of a semigroup: the free semigroup generated by ('a', 'b', 'c', 'd')
                sage: a = S('a')
                sage: a^2
                'aa'
                sage: a.is_idempotent()
                False

            ::

                sage: L = Semigroups().example("leftzero"); L
                An example of a semigroup: the left zero semigroup
                sage: x = L('x')
                sage: x^2
                'x'
                sage: x.is_idempotent()
                True

            """
            return self * self == self

    class CartesianProducts(CartesianProductsCategory):

        def extra_super_categories(self):
            """
            This implements the fact that a subquotient (and therefore
            a quotient or subobject) of a finite set is finite.

            EXAMPLES::

                sage: Semigroups().CartesianProducts().extra_super_categories()
                [Category of semigroups]
                sage: Semigroups().CartesianProducts().super_categories()
                [Category of semigroups, Category of Cartesian products of magmas]
            """
            return [Magmas()]

        def example(self):
            """
            Return an example of Cartesian product of magmas.

            EXAMPLES::

                sage: C = Magmas().CartesianProducts().example(); C
                The Cartesian product of (Rational Field, Integer Ring, Integer Ring)
                sage: C.category()
                Category of Cartesian products of commutative rings
                sage: sorted(C.category().axioms())
                ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveInverse',
                 'AdditiveUnital', 'Associative', 'Commutative',
                 'Distributive', 'Unital']

                sage: TestSuite(C).run()
            """
            from .cartesian_product import cartesian_product
            from sage.rings.integer_ring import ZZ
            from sage.rings.rational_field import QQ
            return cartesian_product([QQ, ZZ, ZZ])

        class ParentMethods:

            def product(self, left, right):
                """
                EXAMPLES::

                    sage: C = Magmas().CartesianProducts().example(); C
                    The Cartesian product of (Rational Field, Integer Ring, Integer Ring)
                    sage: x = C.an_element(); x
                    (1/2, 1, 1)
                    sage: x * x
                    (1/4, 1, 1)

                    sage: A = SymmetricGroupAlgebra(QQ, 3);
                    sage: x = cartesian_product([A([1,3,2]), A([2,3,1])])
                    sage: y = cartesian_product([A([1,3,2]), A([2,3,1])])
                    sage: cartesian_product([A,A]).product(x,y)
                    B[(0, [1, 2, 3])] + B[(1, [3, 1, 2])]
                    sage: x*y
                    B[(0, [1, 2, 3])] + B[(1, [3, 1, 2])]
                """
                return self._cartesian_product_of_elements([(a*b) for (a,b) in zip(left.cartesian_factors(), right.cartesian_factors())])

    class Subquotients(SubquotientsCategory):
        r"""
        The category of subquotient magmas.

        See :meth:`Sets.SubcategoryMethods.Subquotients` for the
        general setup for subquotients. In the case of a subquotient
        magma `S` of a magma `G`, the condition that `r` be a
        morphism in ``As`` can be rewritten as follows:

         - for any two `a,b \in S` the identity
           `a \times_S b = r(l(a) \times_G l(b))` holds.

        This is used by this category to implement the product
        `\times_S` of `S` from `l` and `r` and the product of `G`.

        EXAMPLES::

            sage: Semigroups().Subquotients().all_super_categories()
            [Category of subquotients of semigroups, Category of semigroups,
             Category of subquotients of magmas, Category of magmas,
             Category of subquotients of sets, Category of sets,
             Category of sets with partial maps,
             Category of objects]
        """

        class ParentMethods:

            def product(self, x, y):
                """
                Return the product of two elements of ``self``.

                EXAMPLES::

                    sage: S = Semigroups().Subquotients().example()
                    sage: S
                    An example of a (sub)quotient semigroup:
                    a quotient of the left zero semigroup
                    sage: S.product(S(19), S(3))
                    19

                Here is a more elaborate example involving a sub algebra::

                    sage: Z = SymmetricGroup(5).algebra(QQ).center()
                    sage: B = Z.basis()
                    sage: B[3] * B[2]
                    4*B[2] + 6*B[3] + 5*B[6]
                """
                assert(x in self)
                assert(y in self)
                return self.retract(self.lift(x) * self.lift(y))

    class Realizations(RealizationsCategory):

        class ParentMethods:

            def product_by_coercion(self, left, right):
                r"""
                Default implementation of product for realizations.

                This method coerces to the realization specified by
                ``self.realization_of().a_realization()``, computes
                the product in that realization, and then coerces
                back.

                EXAMPLES::

                    sage: Out = Sets().WithRealizations().example().Out(); Out
                    The subset algebra of {1, 2, 3} over Rational Field in the Out basis
                    sage: Out.product
                    <bound method SubsetAlgebra.Out_with_category.product_by_coercion of The subset algebra of {1, 2, 3} over Rational Field in the Out basis>
                    sage: Out.product.__module__
                    'sage.categories.magmas'
                    sage: x = Out.an_element()
                    sage: y = Out.an_element()
                    sage: Out.product(x, y)
                    Out[{}] + 4*Out[{1}] + 9*Out[{2}] + Out[{1, 2}]

                """
                R = self.realization_of().a_realization()
                return self(R(left) * R(right))
Ejemplo n.º 16
0
class DivisionRings(CategoryWithAxiom):
    """
    The category of division rings

    A division ring (or skew field) is a not necessarily commutative
    ring where all non-zero elements have multiplicative inverses

    EXAMPLES::

      sage: DivisionRings()
      Category of division rings
      sage: DivisionRings().super_categories()
      [Category of domains]

    TESTS::

        sage: TestSuite(DivisionRings()).run()
    """

    # This information could be deduced from the name. It's set here
    # just to get ``division rings`` for the name of the objects of
    # this category and not ``no zero divisors division rings``. See
    # :meth:`Category_with_axiom._repr_object_names` and the ``named``
    # option of :meth:`Category_with_axiom._without_axioms
    _base_category_class_and_axiom = (Rings, "Division")

    def extra_super_categories(self):
        r"""
        Return the :class:`Domains` category.

        This method specifies that a division ring has no zero
        divisors, i.e. is a domain.

        .. SEEALSO::

            The :ref:`axioms-deduction-rules` section in the
            documentation of axioms

        EXAMPLES:

            sage: DivisionRings().extra_super_categories()
            (Category of domains,)
            sage: "NoZeroDivisors" in DivisionRings().axioms()
            True
        """
        return (Rings().NoZeroDivisors(), )

    Commutative = LazyImport('sage.categories.fields',
                             'Fields',
                             at_startup=True)

    def Finite_extra_super_categories(self):
        r"""
        Return extraneous super categories for ``DivisionRings().Finite()``.

        EXAMPLES:

        Any field is a division ring::

            sage: Fields().is_subcategory(DivisionRings())
            True

        This methods specifies that, by Weddeburn theorem, the
        reciprocal holds in the finite case: a finite division ring is
        commutative and thus a field::

            sage: DivisionRings().Finite_extra_super_categories()
            (Category of commutative magmas,)
            sage: DivisionRings().Finite()
            Category of finite fields

        .. WARNING::

            This is not implemented in
            ``DivisionRings.Finite.extra_super_categories`` because
            the categories of finite division rings and of finite
            fields coincide. See the section
            :ref:`axioms-deduction-rules` in the documentation of
            axioms.

        TESTS::

            sage: DivisionRings().Finite() is Fields().Finite()
            True

        This works also for subcategories::

            sage: class Foo(Category):
            ....:     def super_categories(self): return [DivisionRings()]
            sage: Foo().Finite().is_subcategory(Fields())
            True
        """
        from sage.categories.magmas import Magmas
        return (Magmas().Commutative(), )

    class ParentMethods:
        pass

    class ElementMethods:
        pass
Ejemplo n.º 17
0
class MagmasAndAdditiveMagmas(Category_singleton):
    """
    The category of sets `(S,+,*)` with an additive operation '+' and
    a multiplicative operation `*`

    EXAMPLES::

        sage: from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas
        sage: C = MagmasAndAdditiveMagmas(); C
        Category of magmas and additive magmas

    This is the base category for the categories of rings and their variants::

        sage: C.Distributive()
        Category of distributive magmas and additive magmas
        sage: C.Distributive().Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse()
        Category of rngs
        sage: C.Distributive().Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().Unital()
        Category of semirings
        sage: C.Distributive().Associative().AdditiveAssociative().AdditiveCommutative().AdditiveUnital().AdditiveInverse().Unital()
        Category of rings

    This category is really meant to represent the intersection of the
    categories of :class:`Magmas` and :class:`AdditiveMagmas`; however
    Sage's infrastructure does not allow yet to model this::

        sage: Magmas() & AdditiveMagmas()
        Join of Category of magmas and Category of additive magmas

        sage: Magmas() & AdditiveMagmas()        # todo: not implemented
        Category of magmas and additive magmas

    TESTS::

        sage: TestSuite(MagmasAndAdditiveMagmas()).run()
    """

    class SubcategoryMethods:

        @cached_method
        def Distributive(self):
            r"""
            Return the full subcategory of the objects of ``self``
            where `*` is distributive on `+`.

            A :class:`magma <Magmas>` and :class:`additive magma
            <AdditiveMagmas>` `M` is *distributive* if, for all
            `x,y,z \in M`,

            .. MATH::

                x * (y+z) = x*y + x*z \text{ and } (x+y) * z = x*z + y*z

            EXAMPLES::

                sage: from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas
                sage: C = MagmasAndAdditiveMagmas().Distributive(); C
                Category of distributive magmas and additive magmas

            .. NOTE::

                Given that Sage does not know that
                :class:`MagmasAndAdditiveMagmas` is the intersection
                of :class:`Magmas` and :class:`AdditiveMagmas`, this
                method is not available for::

                    sage: Magmas() & AdditiveMagmas()
                    Join of Category of magmas and Category of additive magmas

                Still, the natural syntax works::

                    sage: (Magmas() & AdditiveMagmas()).Distributive()
                    Category of distributive magmas and additive magmas

                thanks to a workaround implemented in
                :meth:`Magmas.SubcategoryMethods.Distributive`::

                    sage: (Magmas() & AdditiveMagmas()).Distributive.__module__
                    'sage.categories.magmas'

            TESTS::

                sage: TestSuite(C).run()
                sage: Fields().Distributive.__module__
                'sage.categories.magmas_and_additive_magmas'
            """
            return self._with_axiom('Distributive')

    def super_categories(self):
        """
        EXAMPLES::

            sage: from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas
            sage: MagmasAndAdditiveMagmas().super_categories()
            [Category of magmas, Category of additive magmas]
        """
        return [Magmas(), AdditiveMagmas()]

    def additional_structure(self):
        r"""
        Return ``None``.

        Indeed, this category is meant to represent the join of
        :class:`AdditiveMagmas` and :class:`Magmas`. As such, it
        defines no additional structure.

        .. SEEALSO:: :meth:`Category.additional_structure`

        EXAMPLES::

            sage: from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas
            sage: MagmasAndAdditiveMagmas().additional_structure()
        """
        return None

    Distributive = LazyImport('sage.categories.distributive_magmas_and_additive_magmas', 'DistributiveMagmasAndAdditiveMagmas', at_startup=True)

    class CartesianProducts(CartesianProductsCategory):
        def extra_super_categories(self):
            r"""
            Implement the fact that this structure is stable under Cartesian
            products.

            TESTS::

                sage: from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas
                sage: MagmasAndAdditiveMagmas().CartesianProducts().extra_super_categories()
                [Category of magmas and additive magmas]
            """
            return [MagmasAndAdditiveMagmas()]
Ejemplo n.º 18
0
class Groups(CategoryWithAxiom):
    """
    The category of (multiplicative) groups, i.e. monoids with
    inverses.

    EXAMPLES::

        sage: Groups()
        Category of groups
        sage: Groups().super_categories()
        [Category of monoids, Category of inverse unital magmas]

    TESTS::

        sage: TestSuite(Groups()).run()
    """
    _base_category_class_and_axiom = (Monoids, "Inverse")

    def example(self):
        """
        EXAMPLES::

            sage: Groups().example()
            General Linear Group of degree 4 over Rational Field
        """
        from sage.rings.rational_field import QQ
        from sage.groups.matrix_gps.linear import GL
        return GL(4,QQ)

    @staticmethod
    def free(index_set=None, names=None, **kwds):
        r"""
        Return the free group.

        INPUT:

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

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

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

        EXAMPLES::

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

        from sage.groups.indexed_free_group import IndexedFreeGroup
        return IndexedFreeGroup(index_set, **kwds)

    class ParentMethods:

        def group_generators(self):
            """
            Return group generators for ``self``.

            This default implementation calls :meth:`gens`, for
            backward compatibility.

            EXAMPLES::

                sage: A = AlternatingGroup(4)
                sage: A.group_generators()
                Family ((2,3,4), (1,2,3))
            """
            from sage.sets.family import Family
            try:
                return Family(self.gens())
            except AttributeError:
                raise NotImplementedError("no generators are implemented for this group")

        def monoid_generators(self):
            r"""
            Return the generators of ``self`` as a monoid.

            Let `G` be a group with generating set `X`. In general, the
            generating set of `G` as a monoid is given by `X \cup X^{-1}`,
            where `X^{-1}` is the set of inverses of `X`. If `G` is a finite
            group, then the generating set as a monoid is `X`.

            EXAMPLES::

                sage: A = AlternatingGroup(4)
                sage: A.monoid_generators()
                Family ((2,3,4), (1,2,3))
                sage: F.<x,y> = FreeGroup()
                sage: F.monoid_generators()
                Family (x, y, x^-1, y^-1)
            """
            G = self.group_generators()
            from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
            if G not in FiniteEnumeratedSets():
                raise NotImplementedError("currently only implemented for finitely generated groups")
            from sage.sets.family import Family
            return Family(tuple(G) + tuple(~x for x in G))

        def _test_inverse(self, **options):
            """
            Run generic tests on the method :meth:`.__invert__`.

            See also: :class:`TestSuite`.

            EXAMPLES::

                sage: G = SymmetricGroup(3)
                sage: G._test_inverse()
            """
            tester = self._tester(**options)
            for x in tester.some_elements():
                tester.assertEqual(x * ~x, self.one())
                tester.assertEqual(~x * x, self.one())

        def semidirect_product(self, N, mapping, check = True):
            r"""
            The semi-direct product of two groups

            EXAMPLES::

                sage: G = Groups().example()
                sage: G.semidirect_product(G,Morphism(G,G))
                Traceback (most recent call last):
                ...
                NotImplementedError: semidirect product of General Linear Group of degree 4 over Rational Field and General Linear Group of degree 4 over Rational Field not yet implemented
            """
            raise NotImplementedError("semidirect product of %s and %s not yet implemented"%(self, N))

        def holomorph(self):
            r"""
            The holomorph of a group

            The holomorph of a group `G` is the semidirect product
            `G \rtimes_{id} Aut(G)`, where `id` is the identity function
            on `Aut(G)`, the automorphism group of `G`.

            See :wikipedia:`Holomorph (mathematics)`

            EXAMPLES::

                sage: G = Groups().example()
                sage: G.holomorph()
                Traceback (most recent call last):
                ...
                NotImplementedError: holomorph of General Linear Group of degree 4 over Rational Field not yet implemented
            """
            raise NotImplementedError("holomorph of %s not yet implemented"%self)

        def cayley_table(self, names='letters', elements=None):
            r"""
            Returns the "multiplication" table of this multiplicative group,
            which is also known as the "Cayley table".

            .. note:: The order of the elements in the row and column
              headings is equal to the order given by the table's
              :meth:`~sage.matrix.operation_table.OperationTable.column_keys`
              method.  The association between the actual elements and the
              names/symbols used in the table can also be retrieved as
              a dictionary with the
              :meth:`~sage.matrix.operation_table.OperationTable.translation`
              method.

            For groups, this routine should behave identically to the
            :meth:`~sage.categories.magmas.Magmas.ParentMethods.multiplication_table`
            method for magmas, which applies in greater generality.

            INPUT:

            - ``names`` - the type of names used, values are:

              * ``'letters'`` - lowercase ASCII letters are used
                for a base 26 representation of the elements'
                positions in the list given by :meth:`list`,
                padded to a common width with leading 'a's.
              * ``'digits'`` - base 10 representation of the
                elements' positions in the list given by
                :meth:`~sage.matrix.operation_table.OperationTable.column_keys`,
                padded to a common width with leading zeros.
              * ``'elements'`` - the string representations
                of the elements themselves.
              * a list - a list of strings, where the length
                of the list equals the number of elements.

            - ``elements`` - default = ``None``.  A list of
              elements of the group, in forms that can be
              coerced into the structure, eg. their string
              representations. This may be used to impose an
              alternate ordering on the elements, perhaps when
              this is used in the context of a particular structure.
              The default is to use whatever ordering is provided by the
              the group, which is reported by the
              :meth:`~sage.matrix.operation_table.OperationTable.column_keys`
              method.  Or the ``elements`` can be a subset
              which is closed under the operation. In particular,
              this can be used when the base set is infinite.

            OUTPUT:
            An object representing the multiplication table.  This is
            an :class:`~sage.matrix.operation_table.OperationTable` object
            and even more documentation can be found there.


            EXAMPLES:

            Permutation groups, matrix groups and abelian groups
            can all compute their multiplication tables.  ::

                sage: G = DiCyclicGroup(3)
                sage: T = G.cayley_table()
                sage: T.column_keys()
                ((), (5,6,7), ..., (1,4,2,3)(5,7))
                sage: T
                *  a b c d e f g h i j k l
                 +------------------------
                a| a b c d e f g h i j k l
                b| b c a e f d i g h l j k
                c| c a b f d e h i g k l j
                d| d e f a b c j k l g h i
                e| e f d b c a l j k i g h
                f| f d e c a b k l j h i g
                g| g h i j k l d e f a b c
                h| h i g k l j f d e c a b
                i| i g h l j k e f d b c a
                j| j k l g h i a b c d e f
                k| k l j h i g c a b f d e
                l| l j k i g h b c a e f d

            ::

                sage: M = SL(2, 2)
                sage: M.cayley_table()
                *  a b c d e f
                 +------------
                a| c e a f b d
                b| d f b e a c
                c| a b c d e f
                d| b a d c f e
                e| f d e b c a
                f| e c f a d b
                <BLANKLINE>

            ::

                sage: A = AbelianGroup([2, 3])
                sage: A.cayley_table()
                *  a b c d e f
                 +------------
                a| a b c d e f
                b| b c a e f d
                c| c a b f d e
                d| d e f a b c
                e| e f d b c a
                f| f d e c a b

            Lowercase ASCII letters are the default symbols used
            for the table, but you can also specify the use of
            decimal digit strings, or provide your own strings
            (in the proper order if they have meaning).
            Also, if the elements themselves are not too complex,
            you can choose to just use the string representations
            of the elements themselves.  ::

                sage: C=CyclicPermutationGroup(11)
                sage: C.cayley_table(names='digits')
                 *  00 01 02 03 04 05 06 07 08 09 10
                  +---------------------------------
                00| 00 01 02 03 04 05 06 07 08 09 10
                01| 01 02 03 04 05 06 07 08 09 10 00
                02| 02 03 04 05 06 07 08 09 10 00 01
                03| 03 04 05 06 07 08 09 10 00 01 02
                04| 04 05 06 07 08 09 10 00 01 02 03
                05| 05 06 07 08 09 10 00 01 02 03 04
                06| 06 07 08 09 10 00 01 02 03 04 05
                07| 07 08 09 10 00 01 02 03 04 05 06
                08| 08 09 10 00 01 02 03 04 05 06 07
                09| 09 10 00 01 02 03 04 05 06 07 08
                10| 10 00 01 02 03 04 05 06 07 08 09

            ::

                sage: G=QuaternionGroup()
                sage: names=['1', 'I', '-1', '-I', 'J', '-K', '-J', 'K']
                sage: G.cayley_table(names=names)
                 *   1  I -1 -I  J -K -J  K
                  +------------------------
                 1|  1  I -1 -I  J -K -J  K
                 I|  I -1 -I  1  K  J -K -J
                -1| -1 -I  1  I -J  K  J -K
                -I| -I  1  I -1 -K -J  K  J
                 J|  J -K -J  K -1 -I  1  I
                -K| -K -J  K  J  I -1 -I  1
                -J| -J  K  J -K  1  I -1 -I
                 K|  K  J -K -J -I  1  I -1

            ::

                sage: A=AbelianGroup([2,2])
                sage: A.cayley_table(names='elements')
                    *      1    f1    f0 f0*f1
                     +------------------------
                    1|     1    f1    f0 f0*f1
                   f1|    f1     1 f0*f1    f0
                   f0|    f0 f0*f1     1    f1
                f0*f1| f0*f1    f0    f1     1

            The :meth:`~sage.matrix.operation_table.OperationTable.change_names`
            routine behaves similarly, but changes an existing table "in-place."
            ::

                sage: G=AlternatingGroup(3)
                sage: T=G.cayley_table()
                sage: T.change_names('digits')
                sage: T
                *  0 1 2
                 +------
                0| 0 1 2
                1| 1 2 0
                2| 2 0 1

            For an infinite group, you can still work with finite sets of
            elements, provided the set is closed under multiplication.
            Elements will be coerced into the group as part of setting
            up the table.  ::

                sage: G=SL(2,ZZ)
                sage: G
                Special Linear Group of degree 2 over Integer Ring
                sage: identity = matrix(ZZ, [[1,0], [0,1]])
                sage: G.cayley_table(elements=[identity, -identity])
                *  a b
                 +----
                a| a b
                b| b a

            The
            :class:`~sage.matrix.operation_table.OperationTable`
            class provides even greater flexibility, including changing
            the operation.  Here is one such example, illustrating the
            computation of commutators.  ``commutator`` is defined as
            a function of two variables, before being used to build
            the table. From this, the commutator subgroup seems obvious,
            and creating a Cayley table with just these three elements
            confirms that they form a closed subset in the group.
            ::

                sage: from sage.matrix.operation_table import OperationTable
                sage: G = DiCyclicGroup(3)
                sage: commutator = lambda x, y: x*y*x^-1*y^-1
                sage: T = OperationTable(G, commutator)
                sage: T
                .  a b c d e f g h i j k l
                 +------------------------
                a| a a a a a a a a a a a a
                b| a a a a a a c c c c c c
                c| a a a a a a b b b b b b
                d| a a a a a a a a a a a a
                e| a a a a a a c c c c c c
                f| a a a a a a b b b b b b
                g| a b c a b c a c b a c b
                h| a b c a b c b a c b a c
                i| a b c a b c c b a c b a
                j| a b c a b c a c b a c b
                k| a b c a b c b a c b a c
                l| a b c a b c c b a c b a

                sage: trans = T.translation()
                sage: comm = [trans['a'], trans['b'], trans['c']]
                sage: comm
                [(), (5,6,7), (5,7,6)]
                sage: P = G.cayley_table(elements=comm)
                sage: P
                *  a b c
                 +------
                a| a b c
                b| b c a
                c| c a b

            .. TODO::

                Arrange an ordering of elements into cosets of a normal
                subgroup close to size `\sqrt{n}`.  Then the quotient
                group structure is often apparent in the table.  See
                comments on :trac:`7555`.

            AUTHOR:

            - Rob Beezer (2010-03-15)

            """
            from sage.matrix.operation_table import OperationTable
            import operator
            return OperationTable(self, operation=operator.mul, names=names, elements=elements)

        def conjugacy_class(self, g):
            r"""
            Return the conjugacy class of the element ``g``.

            This is a fall-back method for groups not defined over GAP.

            EXAMPLES::

                sage: A = AbelianGroup([2,2])
                sage: c = A.conjugacy_class(A.an_element())
                sage: type(c)
                <class 'sage.groups.conjugacy_classes.ConjugacyClass_with_category'>
            """
            from sage.groups.conjugacy_classes import ConjugacyClass
            return ConjugacyClass(self, g)

    class ElementMethods:
        def conjugacy_class(self):
            r"""
            Return the conjugacy class of ``self``.

            EXAMPLES::

                sage: D = DihedralGroup(5)
                sage: g = D((1,3,5,2,4))
                sage: g.conjugacy_class()
                Conjugacy class of (1,3,5,2,4) in Dihedral group of order 10 as a permutation group

                sage: H = MatrixGroup([matrix(GF(5),2,[1,2, -1, 1]), matrix(GF(5),2, [1,1, 0,1])])
                sage: h = H(matrix(GF(5),2,[1,2, -1, 1]))
                sage: h.conjugacy_class()
                Conjugacy class of [1 2]
                [4 1] in Matrix group over Finite Field of size 5 with 2 generators (
                [1 2]  [1 1]
                [4 1], [0 1]
                )

                sage: G = SL(2, GF(2))
                sage: g = G.gens()[0]
                sage: g.conjugacy_class()
                Conjugacy class of [1 1]
                [0 1] in Special Linear Group of degree 2 over Finite Field of size 2

                sage: G = SL(2, QQ)
                sage: g = G([[1,1],[0,1]])
                sage: g.conjugacy_class()
                Conjugacy class of [1 1]
                [0 1] in Special Linear Group of degree 2 over Rational Field
            """
            return self.parent().conjugacy_class(self)

    Finite = LazyImport('sage.categories.finite_groups', 'FiniteGroups', at_startup=True)
    Lie = LazyImport('sage.categories.lie_groups', 'LieGroups', 'Lie')
    Algebras = LazyImport('sage.categories.group_algebras', 'GroupAlgebras', at_startup=True)

    class Commutative(CategoryWithAxiom):
        r"""
        Category of commutative (abelian) groups.

        A group `G` is *commutative* if `xy = yx` for all `x,y \in G`.
        """
        @staticmethod
        def free(index_set=None, names=None, **kwds):
            r"""
            Return the free commutative group.

            INPUT:

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

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

            EXAMPLES::

                sage: Groups.Commutative.free(index_set=ZZ)
                Free abelian group indexed by Integer Ring
                sage: Groups().Commutative().free(ZZ)
                Free abelian group indexed by Integer Ring
                sage: Groups().Commutative().free(5)
                Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
                sage: F.<x,y,z> = Groups().Commutative().free(); F
                Multiplicative Abelian group isomorphic to Z x Z x Z
            """
            from sage.rings.all import ZZ
            if names is not None:
                if isinstance(names, str):
                    if ',' not in names and index_set in ZZ:
                        names = [names + repr(i) for i in range(index_set)]
                    else:
                        names = names.split(',')
                names = tuple(names)
                if index_set is None:
                    index_set = ZZ(len(names))
                if index_set in ZZ:
                    from sage.groups.abelian_gps.abelian_group import AbelianGroup
                    return AbelianGroup(index_set, names=names, **kwds)

            if index_set in ZZ:
                from sage.groups.abelian_gps.abelian_group import AbelianGroup
                return AbelianGroup(index_set, **kwds)

            from sage.groups.indexed_free_group import IndexedFreeAbelianGroup
            return IndexedFreeAbelianGroup(index_set, names=names, **kwds)

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of groups constructed as Cartesian products of groups.

        This construction gives the direct product of groups. See
        :wikipedia:`Direct_product` and :wikipedia:`Direct_product_of_groups`
        for more information.
        """
        def extra_super_categories(self):
            """
            A Cartesian product of groups is endowed with a natural
            group structure.

            EXAMPLES::

                sage: C = Groups().CartesianProducts()
                sage: C.extra_super_categories()
                [Category of groups]
                sage: sorted(C.super_categories(), key=str)
                [Category of Cartesian products of inverse unital magmas,
                 Category of Cartesian products of monoids,
                 Category of groups]
            """
            return [self.base_category()]

        class ParentMethods:
            @cached_method
            def group_generators(self):
                """
                Return the group generators of ``self``.

                EXAMPLES::

                    sage: C5 = CyclicPermutationGroup(5)
                    sage: C4 = CyclicPermutationGroup(4)
                    sage: S4 = SymmetricGroup(3)
                    sage: C = cartesian_product([C5, C4, S4])
                    sage: C.group_generators()
                    Family (((1,2,3,4,5), (), ()),
                            ((), (1,2,3,4), ()),
                            ((), (), (1,2)),
                            ((), (), (2,3)))

                We check the other portion of :trac:`16718` is fixed::

                    sage: len(C.j_classes())
                    1

                An example with an infinitely generated group (a better output
                is needed)::

                    sage: G = Groups.free([1,2])
                    sage: H = Groups.free(ZZ)
                    sage: C = cartesian_product([G, H])
                    sage: C.monoid_generators()
                    Lazy family (gen(i))_{i in The Cartesian product of (...)}
                """
                F = self.cartesian_factors()
                ids = tuple(G.one() for G in F)
                def lift(i, gen):
                    cur = list(ids)
                    cur[i] = gen
                    return self._cartesian_product_of_elements(cur)
                from sage.sets.family import Family

                # Finitely generated
                cat = FiniteEnumeratedSets()
                if all(G.group_generators() in cat
                       or isinstance(G.group_generators(), (tuple, list)) for G in F):
                    ret = [lift(i, gen) for i,G in enumerate(F) for gen in G.group_generators()]
                    return Family(ret)

                # Infinitely generated
                # This does not return a good output, but it is "correct"
                # TODO: Figure out a better way to do things
                gens_prod = cartesian_product([Family(G.group_generators(),
                                                      lambda g: (i, g))
                                               for i,G in enumerate(F)])
                return Family(gens_prod, lift, name="gen")

            def order(self):
                r"""
                Return the cardinality of self.

                EXAMPLES::

                    sage: C = cartesian_product([SymmetricGroup(10), SL(2,GF(3))])
                    sage: C.order()
                    87091200

                TESTS::

                    sage: C.order.__module__
                    'sage.categories.groups'

                .. TODO::

                    this method is just here to prevent
                    ``FiniteGroups.ParentMethods`` to call
                    ``_cardinality_from_iterator``.
                """
                from sage.misc.misc_c import prod
                return prod(c.cardinality() for c in self.cartesian_factors())

        class ElementMethods:
            def multiplicative_order(self):
                r"""
                Return the multiplicative order of this element.

                EXAMPLES::

                    sage: G1 = SymmetricGroup(3)
                    sage: G2 = SL(2,3)
                    sage: G = cartesian_product([G1,G2])
                    sage: G((G1.gen(0), G2.gen(1))).multiplicative_order()
                    12
                """
                from sage.rings.infinity import Infinity
                orders = [x.multiplicative_order() for x in self.cartesian_factors()]
                if any(o is Infinity for o in orders):
                    return Infinity
                else:
                    from sage.arith.functions import LCM_list
                    return LCM_list(orders)

    class Topological(TopologicalSpacesCategory):
        """
Ejemplo n.º 19
0
class Algebras(CategoryWithAxiom_over_base_ring):
    r"""
    The category of associative and unital algebras over a given base ring.

    An associative and unital algebra over a ring `R` is a module over
    `R` which is itself a ring.

    .. WARNING::

        :class:`Algebras` will be eventually be replaced by
        :class:`.magmatic_algebras.MagmaticAlgebras`
        for consistency with e.g. :wikipedia:`Algebras` which assumes
        neither associativity nor the existence of a unit (see
        :trac:`15043`).

    .. TODO:: Should `R` be a commutative ring?

    EXAMPLES::

        sage: Algebras(ZZ)
        Category of algebras over Integer Ring
        sage: sorted(Algebras(ZZ).super_categories(), key=str)
        [Category of associative algebras over Integer Ring,
         Category of rings,
         Category of unital algebras over Integer Ring]

    TESTS::

        sage: TestSuite(Algebras(ZZ)).run()
    """
    _base_category_class_and_axiom = (AssociativeAlgebras, 'Unital')

    # For backward compatibility?
    def __contains__(self, x):
        """
        Membership testing

        EXAMPLES::

            sage: QQ['x'] in Algebras(QQ)
            True

            sage: QQ^3 in Algebras(QQ)
            False
            sage: QQ['x'] in Algebras(CDF)
            False
        """
        if super(Algebras, self).__contains__(x):
            return True
        from sage.rings.ring import Algebra
        return isinstance(x, Algebra) and x.base_ring() == self.base_ring()

    # def extra_super_categories(self):
    #     """
    #     EXAMPLES::

    #         sage: Algebras(ZZ).super_categories()
    #         [Category of associative algebras over Integer Ring, Category of rings]
    #     """
    #     R = self.base_ring()
    #     return [Rings()] # TODO: won't be needed when Rings() will be Rngs().Unital()

    class SubcategoryMethods:
        def Semisimple(self):
            """
            Return the subcategory of semisimple objects of ``self``.

            .. NOTE::

                This mimics the syntax of axioms for a smooth
                transition if ``Semisimple`` becomes one.

            EXAMPLES::

                sage: Algebras(QQ).Semisimple()
                Category of semisimple algebras over Rational Field
                sage: Algebras(QQ).WithBasis().FiniteDimensional().Semisimple()
                Category of finite dimensional semisimple algebras with basis over Rational Field
            """
            from sage.categories.semisimple_algebras import SemisimpleAlgebras
            return self & SemisimpleAlgebras(self.base_ring())

    Commutative = LazyImport('sage.categories.commutative_algebras',
                             'CommutativeAlgebras',
                             at_startup=True)
    Filtered = LazyImport('sage.categories.filtered_algebras',
                          'FilteredAlgebras')
    Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras')
    Super = LazyImport('sage.categories.super_algebras', 'SuperAlgebras')
    # at_startup currently needed for MatrixSpace, see #22955 (e.g., comment:20)
    WithBasis = LazyImport('sage.categories.algebras_with_basis',
                           'AlgebrasWithBasis',
                           at_startup=True)
    #if/when Semisimple becomes an axiom
    Semisimple = LazyImport('sage.categories.semisimple_algebras',
                            'SemisimpleAlgebras')

    class ElementMethods:
        # TODO: move the content of AlgebraElement here or higher in the category hierarchy
        def _div_(self, y):
            """
            Division by invertible elements

            # TODO: move in Monoids

            EXAMPLES::

                sage: C = AlgebrasWithBasis(QQ).example()
                sage: x = C(2); x
                2*B[word: ]
                sage: y = C.algebra_generators().first(); y
                B[word: a]

                sage: y._div_(x)
                1/2*B[word: a]
                sage: x._div_(y)
                Traceback (most recent call last):
                ...
                ValueError: cannot invert self (= B[word: a])
            """
            return self.parent().product(self, ~y)

    class Quotients(QuotientsCategory):
        class ParentMethods:
            def algebra_generators(self):
                r"""
                Return algebra generators for ``self``.

                This implementation retracts the algebra generators
                from the ambient algebra.

                EXAMPLES::

                    sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A
                    An example of a finite dimensional algebra with basis:
                    the path algebra of the Kronecker quiver
                    (containing the arrows a:x->y and b:x->y) over Rational Field
                    sage: S = A.semisimple_quotient()
                    sage: S.algebra_generators()
                    Finite family {'y': B['y'], 'x': B['x'], 'b': 0, 'a': 0}

                .. TODO:: this could possibly remove the elements that retract to zero.
                """
                return self.ambient().algebra_generators().map(self.retract)

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of algebras constructed as Cartesian products of algebras

        This construction gives the direct product of algebras. See
        discussion on:

         - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16
         - http://en.wikipedia.org/wiki/Direct_product
        """
        def extra_super_categories(self):
            """
            A Cartesian product of algebras is endowed with a natural
            algebra structure.

            EXAMPLES::

                sage: C = Algebras(QQ).CartesianProducts()
                sage: C.extra_super_categories()
                [Category of algebras over Rational Field]
                sage: sorted(C.super_categories(), key=str)
                [Category of Cartesian products of distributive magmas and additive magmas,
                 Category of Cartesian products of monoids,
                 Category of Cartesian products of vector spaces over Rational Field,
                 Category of algebras over Rational Field]
            """
            return [self.base_category()]

    class TensorProducts(TensorProductsCategory):
        @cached_method
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Algebras(QQ).TensorProducts().extra_super_categories()
                [Category of algebras over Rational Field]
                sage: Algebras(QQ).TensorProducts().super_categories()
                [Category of algebras over Rational Field,
                 Category of tensor products of vector spaces over Rational Field]

            Meaning: a tensor product of algebras is an algebra
            """
            return [self.base_category()]

        class ParentMethods:
            #def coproduct(self):
            #    tensor products of morphisms are not yet implemented
            #    return tensor(module.coproduct for module in self.modules)
            pass

        class ElementMethods:
            pass

    class DualObjects(DualObjectsCategory):
        def extra_super_categories(self):
            r"""
            Returns the dual category

            EXAMPLES:

            The category of algebras over the Rational Field is dual
            to the category of coalgebras over the same field::

                sage: C = Algebras(QQ)
                sage: C.dual()
                Category of duals of algebras over Rational Field
                sage: C.dual().extra_super_categories()
                [Category of coalgebras over Rational Field]

            .. WARNING::

                This is only correct in certain cases (finite dimension, ...).
                See :trac:`15647`.
            """
            from sage.categories.coalgebras import Coalgebras
            return [Coalgebras(self.base_category().base_ring())]
Ejemplo n.º 20
0
class EnumeratedSets(Category_singleton):
    """
    The category of enumerated sets

    An *enumerated set* is a *finite* or *countable* set or multiset `S`
    together with a canonical enumeration of its elements;
    conceptually, this is very similar to an immutable list. The main
    difference lies in the names and the return type of the methods,
    and of course the fact that the list of elements is not supposed to
    be expanded in memory. Whenever possible one should use one of the
    two sub-categories :class:`FiniteEnumeratedSets` or
    :class:`InfiniteEnumeratedSets`.

    The purpose of this category is threefold:

     - to fix a common interface for all these sets;
     - to provide a bunch of default implementations;
     - to provide consistency tests.

    The standard methods for an enumerated set ``S`` are:

       - ``S.cardinality()``: the number of elements of the set. This
         is the equivalent for ``len`` on a list except that the
         return value is specified to be a Sage :class:`Integer` or
         ``infinity``, instead of a Python ``int``.

       - ``iter(S)``: an iterator for the elements of the set;

       - ``S.list()``: the list of the elements of the set, when
         possible; raises a NotImplementedError if the list is
         predictably too large to be expanded in memory.

       - ``S.unrank(n)``: the  ``n-th`` element of the set when ``n`` is a sage
         ``Integer``. This is the equivalent for ``l[n]`` on a list.

       - ``S.rank(e)``: the position of the element ``e`` in the set;
         This is equivalent to ``l.index(e)`` for a list except that
         the return value is specified to be a Sage :class:`Integer`,
         instead of a Python ``int``.

       - ``S.first()``: the first object of the set; it is equivalent to
         ``S.unrank(0)``.

       - ``S.next(e)``: the object of the set which follows ``e``; It is
         equivalent to ``S.unrank(S.rank(e)+1)``.

       - ``S.random_element()``: a random generator for an element of
         the set. Unless otherwise stated, and for finite enumerated
         sets, the probability is uniform.

    For examples and tests see:

       - ``FiniteEnumeratedSets().example()``
       - ``InfiniteEnumeratedSets().example()``


    EXAMPLES::

        sage: EnumeratedSets()
        Category of enumerated sets
        sage: EnumeratedSets().super_categories()
        [Category of sets]
        sage: EnumeratedSets().all_super_categories()
        [Category of enumerated sets, Category of sets, Category of sets with partial maps, Category of objects]

    TESTS::

        sage: C = EnumeratedSets()
        sage: TestSuite(C).run()
    """
    def super_categories(self):
        """
        EXAMPLES::

            sage: EnumeratedSets().super_categories()
            [Category of sets]
        """
        return [Sets()]

    def additional_structure(self):
        """
        Return ``None``.

        Indeed, morphisms of enumerated sets are not required to
        preserve the enumeration.

        .. SEEALSO:: :meth:`Category.additional_structure`

        EXAMPLES::

            sage: EnumeratedSets().additional_structure()
        """
        return None

    def _call_(self, X):
        """
        Construct an object in this category from the data in ``X``.

        EXAMPLES::

            sage: EnumeratedSets()(Primes())
            Set of all prime numbers: 2, 3, 5, 7, ...

        For now, lists, tuples, sets, Sets are coerced into finite
        enumerated sets::

            sage: S = EnumeratedSets()([1, 2, 3]); S
            {1, 2, 3}
            sage: S.category()
            Category of facade finite enumerated sets

            sage: S = EnumeratedSets()((1, 2, 3)); S
            {1, 2, 3}
            sage: S = EnumeratedSets()(set([1, 2, 3])); S
            {1, 2, 3}
            sage: S = EnumeratedSets()(Set([1, 2, 3])); S
            {1, 2, 3}
            sage: S.category()
            Category of facade finite enumerated sets
        """
        import sage.sets.set
        if isinstance(X,
                      (tuple, list, set, sage.sets.set.Set_object_enumerated)):
            return sage.sets.all.FiniteEnumeratedSet(X)
        raise NotImplementedError

    class ParentMethods:
        def __iter__(self):
            """
            An iterator for the enumerated set.

            ``iter(self)`` allows the combinatorial class to be treated as an
            iterable. This is the default implementation from the category
            ``EnumeratedSets()``; it just goes through the iterator of the set
            to count the number of objects.

            By decreasing order of priority, the second column of the
            following array shows which method is used to define
            ``__iter__``, when the methods of the first column are overloaded:

            +------------------------+---------------------------------+
            | Needed methods         | Default ``__iterator`` provided |
            +========================+=================================+
            | ``first`` and ``next`` | ``_iterator_from_next``         |
            +------------------------+---------------------------------+
            | ``unrank``             | ``_iterator_from_unrank``       |
            +------------------------+---------------------------------+
            | ``list`                | ``_iterator_from_next``         |
            +------------------------+---------------------------------+

            If none of these are provided, raise a ``NotImplementedError``.

            EXAMPLES::

            We start with an example where nothing is implemented::

                sage: class broken(UniqueRepresentation, Parent):
                ....:     def __init__(self):
                ....:         Parent.__init__(self, category = EnumeratedSets())
                ....:
                sage: it = iter(broken()); [next(it), next(it), next(it)]
                Traceback (most recent call last):
                ...
                NotImplementedError: iterator called but not implemented

            Here is what happens when ``first`` and ``next`` are implemented::

                sage: class set_first_next(UniqueRepresentation, Parent):
                ....:     def __init__(self):
                ....:         Parent.__init__(self, category = EnumeratedSets())
                ....:     def first(self):
                ....:         return 0
                ....:     def next(self, elt):
                ....:         return elt+1
                ....:
                sage: it = iter(set_first_next()); [next(it), next(it), next(it)]
                [0, 1, 2]

            Let us try with ``unrank``::

                sage: class set_unrank(UniqueRepresentation, Parent):
                ....:     def __init__(self):
                ....:         Parent.__init__(self, category = EnumeratedSets())
                ....:     def unrank(self, i):
                ....:         return i + 5
                ....:
                sage: it = iter(set_unrank()); [next(it), next(it), next(it)]
                [5, 6, 7]

            Let us finally try with ``list``::

                sage: class set_list(UniqueRepresentation, Parent):
                ....:     def __init__(self):
                ....:         Parent.__init__(self, category = EnumeratedSets())
                ....:     def list(self):
                ....:         return [5, 6, 7]
                ....:
                sage: it = iter(set_list()); [next(it), next(it), next(it)]
                [5, 6, 7]

            """
            # Check if .first() and .next(x) are overridden in the subclass
            if (self.first != self._first_from_iterator
                    and self.next != self._next_from_iterator):
                return self._iterator_from_next()
            #Check to see if .unrank() is overridden in the subclass
            elif self.unrank != self._unrank_from_iterator:
                return self._iterator_from_unrank()
            #Finally, check to see if .list() is overridden in the subclass
            elif self.list != self._list_default:
                return self._iterator_from_list()
            else:
                raise NotImplementedError(
                    "iterator called but not implemented")

        def is_empty(self):
            r"""
            Return whether this set is empty.

            EXAMPLES::

                sage: F = FiniteEnumeratedSet([1,2,3])
                sage: F.is_empty()
                False
                sage: F = FiniteEnumeratedSet([])
                sage: F.is_empty()
                True

            TESTS::

                sage: F.is_empty.__module__
                'sage.categories.enumerated_sets'
            """
            try:
                next(iter(self))
            except StopIteration:
                return True
            else:
                return False

        def list(self):
            """
            Return an error since the cardinality of ``self`` is not known.

            EXAMPLES::

                sage: class broken(UniqueRepresentation, Parent):
                ...    def __init__(self):
                ...        Parent.__init__(self, category = EnumeratedSets())
                ...
                sage: broken().list()
                Traceback (most recent call last):
                ...
                NotImplementedError: unknown cardinality
            """
            raise NotImplementedError("unknown cardinality")

        _list_default = list  # needed by the check system.

        def _first_from_iterator(self):
            """
            The "first" element of ``self``.

            ``self.first()`` returns the first element of the set
            ``self``. This is a generic implementation from the category
            ``EnumeratedSets()`` which can be used when the method ``__iter__`` is
            provided.

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: C.first() # indirect doctest
                1
            """
            return next(iter(self))

        first = _first_from_iterator

        def _next_from_iterator(self, obj):
            """
            The "next" element after ``obj`` in ``self``.

            ``self.next(e)`` returns the element of the set ``self`` which
            follows ``e``. This is a generic implementation from the category
            ``EnumeratedSets()`` which can be used when the method ``__iter__``
            is provided.

            Remark: this is the default (brute force) implementation
            of the category ``EnumeratedSets()``. Its complexity is
            `O(r)`, where `r` is the rank of ``obj``.

            EXAMPLES::

                sage: C = InfiniteEnumeratedSets().example()
                sage: C._next_from_iterator(10) # indirect doctest
                11

            TODO: specify the behavior when ``obj`` is not in ``self``.
            """
            it = iter(self)
            el = next(it)
            while el != obj:
                el = next(it)
            return next(it)

        next = _next_from_iterator

        def _unrank_from_iterator(self, r):
            """
            The ``r``-th element of ``self``

            ``self.unrank(r)`` returns the ``r``-th element of self, where
            ``r`` is an integer between ``0`` and ``n-1`` where ``n`` is the
            cardinality of ``self``.

            This is the default (brute force) implementation from the
            category ``EnumeratedSets()`` which can be used when the
            method ``__iter__`` is provided. Its complexity is `O(r)`,
            where `r` is the rank of ``obj``.

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: C.unrank(2) # indirect doctest
                3
                sage: C._unrank_from_iterator(5)
                Traceback (most recent call last):
                ...
                ValueError: the value must be between 0 and 2 inclusive
            """
            counter = 0
            for u in self:
                if counter == r:
                    return u
                counter += 1
            raise ValueError("the value must be between %s and %s inclusive" %
                             (0, counter - 1))

        unrank = _unrank_from_iterator

        def _rank_from_iterator(self, x):
            """
            The rank of an element of ``self``

            ``self.rank(x)`` returns the rank of `x`, that is its
            position in the enumeration of ``self``. This is an
            integer between ``0`` and ``n-1`` where ``n`` is the
            cardinality of ``self``, or None if `x` is not in `self`.

            This is the default (brute force) implementation from the
            category ``EnumeratedSets()`` which can be used when the
            method ``__iter__`` is provided. Its complexity is `O(r)`,
            where `r` is the rank of ``obj``. For infinite enumerated
            sets, this won't terminate when `x` is not in ``self``

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: list(C)
                [1, 2, 3]
                sage: C.rank(3) # indirect doctest
                2
                sage: C.rank(5) # indirect doctest
            """
            counter = 0
            for u in self:
                if u == x:
                    return counter
                counter += 1
            return None

        rank = _rank_from_iterator

        def _iterator_from_list(self):
            """
            An iterator for the elements of ``self``.

            ``iter(self)`` returns an iterator for the elements
            of ``self``. This is a generic implementation from the
            category ``EnumeratedSets()`` which can be used when the
            method ``list`` is provided.

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: it = C._iterator_from_list()
                sage: [next(it), next(it), next(it)]
                [1, 2, 3]
            """
            for x in self.list():
                yield x

        def _iterator_from_next(self):
            """
            An iterator for the elements of ``self``.

            ``iter(self)`` returns an iterator for the element of
            the set ``self``. This is a generic implementation from
            the category ``EnumeratedSets()`` which can be used when
            the methods ``first`` and ``next`` are provided.

            EXAMPLES::

                sage: C = InfiniteEnumeratedSets().example()
                sage: it = C._iterator_from_next()
                sage: [next(it), next(it), next(it), next(it), next(it)]
                [0, 1, 2, 3, 4]
            """
            f = self.first()
            yield f
            while True:
                try:
                    f = self.next(f)
                except (TypeError, ValueError):
                    break

                if f is None or f is False:
                    break
                else:
                    yield f

        def _iterator_from_unrank(self):
            """
            An iterator for the elements of ``self``.

            ``iter(self)`` returns an iterator for the elements
            of the set ``self``. This is a generic implementation from
            the category ``EnumeratedSets()`` which can be used when
            the method ``unrank`` is provided.

            EXAMPLES::

                sage: C = InfiniteEnumeratedSets().example()
                sage: it = C._iterator_from_unrank()
                sage: [next(it), next(it), next(it), next(it), next(it)]
                [0, 1, 2, 3, 4]
            """
            r = 0
            try:
                u = self.unrank(r)
            except (TypeError, ValueError, IndexError):
                return
            yield u
            while True:
                r += 1
                try:
                    u = self.unrank(r)
                except (TypeError, ValueError, IndexError):
                    break

                if u is None:
                    break
                else:
                    yield u

        # This @cached_method is not really needed, since the method
        # an_element itself is cached. We leave it for the moment, so
        # that Parents that do not yet inherit properly from categories
        # (e.g. Set([1,2,3]) can use the following trick:
        #    _an_element_ = EnumeratedSets.ParentMethods._an_element_
        @cached_method
        def _an_element_from_iterator(self):
            """
            Return the first element of ``self`` returned by :meth:`__iter__`

            If ``self`` is empty, the exception
            :class:`~sage.categories.sets_cat.EmptySetError` is raised instead.

            This provides a generic implementation of the method
            :meth:`_an_element_` for all parents in :class:`EnumeratedSets`.

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example(); C
                An example of a finite enumerated set: {1,2,3}
                sage: C.an_element() # indirect doctest
                1
                sage: S = Set([])
                sage: S.an_element()
                Traceback (most recent call last):
                ...
                EmptySetError

            TESTS::

                sage: super(Parent, C)._an_element_
                Cached version of <function _an_element_from_iterator at ...>
            """
            it = iter(self)
            try:
                return next(it)
            except StopIteration:
                raise EmptySetError

        # Should this be implemented from first instead?
        _an_element_ = _an_element_from_iterator

        #FIXME: use combinatorial_class_from_iterator once class_from_iterator.patch is in
        def _some_elements_from_iterator(self):
            """
            Return some elements in ``self``.

            See :class:`TestSuite` for a typical use case.

            This is a generic implementation from the category
            ``EnumeratedSets()`` which can be used when the method
            ``__iter__`` is provided. It returns an iterator for up to
            the first 100 elements of ``self``

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: list(C.some_elements()) # indirect doctest
                [1, 2, 3]
            """
            nb = 0
            for i in self:
                yield i
                nb += 1
                if nb >= 100:
                    break

        some_elements = _some_elements_from_iterator

        def random_element(self):
            """
            Return a random element in ``self``.

            Unless otherwise stated, and for finite enumerated sets,
            the probability is uniform.

            This is a generic implementation from the category
            ``EnumeratedSets()``. It raise a ``NotImplementedError``
            since one does not know whether the set is finite.

            EXAMPLES::

                sage: class broken(UniqueRepresentation, Parent):
                ...    def __init__(self):
                ...        Parent.__init__(self, category = EnumeratedSets())
                ...
                sage: broken().random_element()
                Traceback (most recent call last):
                ...
                NotImplementedError: unknown cardinality
                """
            raise NotImplementedError("unknown cardinality")

        def map(self, f, name=None):
            r"""
            Return the image `\{f(x) | x \in \text{self}\}` of this
            enumerated set by `f`, as an enumerated set.

            `f` is supposed to be injective.

            EXAMPLES::

                sage: R = SymmetricGroup(3).map(attrcall('reduced_word')); R
                Image of Symmetric group of order 3! as a permutation group by *.reduced_word()
                sage: R.cardinality()
                6
                sage: R.list()
                [[], [1], [2, 1], [1, 2], [2], [1, 2, 1]]
                sage: [ r for r in R]
                [[], [1], [2, 1], [1, 2], [2], [1, 2, 1]]

            .. warning::

                If the function is not injective, then there may be
                repeated elements::

                    sage: P = SymmetricGroup(3)
                    sage: P.list()
                    [(), (1,2), (1,2,3), (1,3,2), (2,3), (1,3)]
                    sage: P.map(attrcall('length')).list()
                    [0, 1, 2, 2, 1, 3]

            .. warning::

                :class:`MapCombinatorialClass` needs to be refactored to use categories::

                    sage: R.category()             # todo: not implemented
                    Category of enumerated sets
                    sage: TestSuite(R).run(skip=['_test_an_element', '_test_category', '_test_some_elements'])
            """
            from sage.combinat.combinat import MapCombinatorialClass
            return MapCombinatorialClass(self, f, name)

#
#  Consistency test suite for an enumerated set:
#

        def _test_enumerated_set_contains(self, **options):
            """
            Checks that the methods :meth:`.__contains__` and :meth:`.__iter__` are consistent.

            See also :class:`TestSuite`.

            TESTS::

                sage: C = FiniteEnumeratedSets().example()
                sage: C._test_enumerated_set_contains()
                sage: TestSuite(C).run()

            Let us now break the class::

                sage: from sage.categories.examples.finite_enumerated_sets import Example
                sage: class CCls(Example):
                ...       def __contains__(self, obj):
                ...           if obj == 3:
                ...               return False
                ...           else:
                ...               return obj in C
                sage: CC = CCls()
                sage: CC._test_enumerated_set_contains()
                Traceback (most recent call last):
                ...
                AssertionError: False is not true
            """
            tester = self._tester(**options)
            i = 0
            for w in self:
                tester.assertTrue(w in self)
                i += 1
                if i > tester._max_runs:
                    return

        def _test_enumerated_set_iter_list(self, **options):
            """
            Checks that the methods :meth:`.list` and :meth:`.__iter__` are consistent.

            See also: :class:`TestSuite`.

            .. NOTE::

                This test does nothing if the cardinality of the set
                is larger than the max_runs argument.

            EXAMPLES::

                sage: C = FiniteEnumeratedSets().example()
                sage: C._test_enumerated_set_iter_list()
                sage: TestSuite(C).run()

            Let us now break the class::

                sage: from sage.categories.examples.finite_enumerated_sets import Example
                sage: class CCls(Example):
                ...       def list(self):
                ...           return [1,2,3,4]
                sage: CC = CCls()
                sage: CC._test_enumerated_set_iter_list()
                Traceback (most recent call last):
                ...
                AssertionError: 3 != 4

            For a large enumerated set this test does nothing:
            increase tester._max_runs if you want to actually run the
            test::

                sage: class CCls(Example):
                ...       def list(self):
                ...           return [1,2,3]
                sage: CC = CCls()
                sage: CC._test_enumerated_set_iter_list(verbose=True,max_runs=2)
                Enumerated set too big; skipping test; increase tester._max_runs
            """
            tester = self._tester(**options)
            if self.list != self._list_default:
                # TODO: if self._cardinality is self._cardinality_from_iterator
                # we could make sure to stop the counting at
                # self.max_test_enumerated_set_loop
                if self.cardinality() > tester._max_runs:
                    tester.info(
                        "Enumerated set too big; skipping test; increase tester._max_runs"
                    )
                    return
                ls = self.list()
                i = 0
                for obj in self:
                    tester.assertEqual(obj, ls[i])
                    i += 1
                tester.assertEqual(i, len(ls))

    class ElementMethods:
        def rank(self):
            """
            Return the rank of ``self`` in its parent.

            See also :meth:`EnumeratedSets.ElementMethods.rank`

            EXAMPLES::

                sage: F = FiniteSemigroups().example(('a','b','c'))
                sage: L = list(F); L
                ['a', 'b', 'c', 'ac', 'ab', 'ba', 'bc', 'cb', 'ca',
                 'acb', 'abc', 'bca', 'cba', 'bac', 'cab']
                sage: L[7].rank()
                7
            """
            return self.parent().rank(self)

    Finite = LazyImport('sage.categories.finite_enumerated_sets',
                        'FiniteEnumeratedSets',
                        at_startup=True)
    Infinite = LazyImport('sage.categories.infinite_enumerated_sets',
                          'InfiniteEnumeratedSets',
                          at_startup=True)

    class CartesianProducts(CartesianProductsCategory):
        class ParentMethods:
            def first(self):
                r"""
                Return the first element.

                EXAMPLES::

                    sage: cartesian_product([ZZ]*10).first()
                    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
                """
                return self._cartesian_product_of_elements(
                    tuple(c.first() for c in self.cartesian_factors()))
Ejemplo n.º 21
0
class Monoids(CategoryWithAxiom):
    r"""
    The category of (multiplicative) monoids.

    A *monoid* is a unital :class:`semigroup <Semigroups>`, that is a
    set endowed with a multiplicative binary operation `*` which is
    associative and admits a unit (see :wikipedia:`Monoid`).

    EXAMPLES::

        sage: Monoids()
        Category of monoids
        sage: Monoids().super_categories()
        [Category of semigroups, Category of unital magmas]
        sage: Monoids().all_super_categories()
        [Category of monoids,
         Category of semigroups,
         Category of unital magmas, Category of magmas,
         Category of sets,
         Category of sets with partial maps,
         Category of objects]

        sage: Monoids().axioms()
        frozenset({'Associative', 'Unital'})
        sage: Semigroups().Unital()
        Category of monoids

        sage: Monoids().example()
        An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd')

    TESTS::

        sage: C = Monoids()
        sage: TestSuite(C).run()

    """

    _base_category_class_and_axiom = (Semigroups, "Unital")

    Finite = LazyImport('sage.categories.finite_monoids', 'FiniteMonoids', at_startup=True)
    Inverse = LazyImport('sage.categories.groups', 'Groups', at_startup=True)

    @staticmethod
    def free(index_set=None, names=None, **kwds):
        r"""
        Return a free monoid on `n` generators or with the generators
        indexed by a set `I`.

        A free monoid is constructed by specifing either:

        - the number of generators and/or the names of the generators
        - the indexing set for the generators

        INPUT:

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

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

        EXAMPLES::

            sage: Monoids.free(index_set=ZZ)
            Free monoid indexed by Integer Ring
            sage: Monoids().free(ZZ)
            Free monoid indexed by Integer Ring
            sage: F.<x,y,z> = Monoids().free(); F
            Free monoid indexed by {'x', 'y', 'z'}
        """
        if names is not None:
            if isinstance(names, str):
                from sage.rings.all import ZZ
                if ',' not in names and index_set in ZZ:
                    names = [names + repr(i) for i in range(index_set)]
                else:
                    names = names.split(',')
            names = tuple(names)
            if index_set is None:
                index_set = names

        from sage.monoids.indexed_free_monoid import IndexedFreeMonoid
        return IndexedFreeMonoid(index_set, names=names, **kwds)

    class ParentMethods:

        def one_element(self):
            r"""
            Backward compatibility alias for :meth:`one`.

            TESTS::

                sage: S = Monoids().example()
                sage: S.one_element()
                doctest:...: DeprecationWarning: .one_element() is deprecated. Please use .one() instead.
                See http://trac.sagemath.org/17694 for details.
                ''
            """
            from sage.misc.superseded import deprecation
            deprecation(17694, ".one_element() is deprecated. Please use .one() instead.")
            return self.one()

        def semigroup_generators(self):
            """
            Return the generators of ``self`` as a semigroup.

            The generators of a monoid `M` as a semigroup are the generators
            of `M` as a monoid and the unit.

            EXAMPLES::

                sage: M = Monoids().free([1,2,3])
                sage: M.semigroup_generators()
                Family (1, F[1], F[2], F[3])
            """
            G = self.monoid_generators()
            from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
            if G not in FiniteEnumeratedSets():
                raise NotImplementedError("currently only implemented for finitely generated monoids")
            from sage.sets.family import Family
            return Family((self.one(),) + tuple(G))

        def prod(self, args):
            r"""
            n-ary product of elements of ``self``.

            INPUT:

            - ``args`` -- a list (or iterable) of elements of ``self``

            Returns the product of the elements in ``args``, as an element of
            ``self``.

            EXAMPLES::

                sage: S = Monoids().example()
                sage: S.prod([S('a'), S('b')])
                'ab'
            """
            return prod(args, self.one())

        def _test_prod(self, **options):
            r"""
            Run basic tests for the product method :meth:`prod` of ``self``.

            See the documentation for :class:`TestSuite` for information on
            further options.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`

            EXAMPLES:

            By default, this method tests only the elements returned by
            ``self.some_elements()``::

                sage: S = Monoids().example()
                sage: S._test_prod()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: S._test_prod(elements = (S('a'), S('b')))
            """
            tester = self._tester(**options)
            tester.assert_(self.prod([]) == self.one())
            for x in tester.some_elements():
                tester.assert_(self.prod([x]) == x)
                tester.assert_(self.prod([x, x]) == x**2)
                tester.assert_(self.prod([x, x, x]) == x**3)


        def submonoid(self, generators, category=None):
            r"""
            Return the multiplicative submonoid generated by ``generators``.

            INPUT:

            - ``generators`` -- a finite family of elements of
              ``self``, or a list, iterable, ... that can be converted
              into one (see :class:`Family`).

            - ``category`` -- a category

            This is a shorthand for
            :meth:`Semigroups.ParentMethods.subsemigroup` that
            specifies that this is a submonoid, and in particular that
            the unit is ``self.one()``.

            EXAMPLES::

                sage: R = IntegerModRing(15)
                sage: M = R.submonoid([R(3),R(5)]); M
                A submonoid of (Ring of integers modulo 15) with 2 generators
                sage: M.list()
                [1, 3, 5, 9, 0, 10, 12, 6]

            Not the presence of the unit, unlike in::

                sage: S = R.subsemigroup([R(3),R(5)]); S
                A subsemigroup of (Ring of integers modulo 15) with 2 generators
                sage: S.list()
                [3, 5, 9, 0, 10, 12, 6]

            This method is really a shorthand for subsemigroup::

                sage: M2 = R.subsemigroup([R(3),R(5)], one=R.one())
                sage: M2 is M
                True


            """
            return self.subsemigroup(generators, one=self.one())

    class ElementMethods:

        def is_one(self):
            r"""
            Return whether ``self`` is the one of the monoid.

            The default implementation is to compare with ``self.one()``.

            TESTS::

                sage: S = Monoids().example()
                sage: S.one().is_one()
                True
                sage: S("aa").is_one()
                False
            """
            return self == self.parent().one()

        def __pow__(self, n):
            r"""
            Return ``self`` to the `n^{th}` power.

            INPUT:

            - ``n`` -- a nonnegative integer

            EXAMPLES::

                sage: S = Monoids().example()
                sage: x = S("aa")
                sage: x^0, x^1, x^2, x^3, x^4, x^5
                ('', 'aa', 'aaaa', 'aaaaaa', 'aaaaaaaa', 'aaaaaaaaaa')

            """
            if not n: # FIXME: why do we need to do that?
                return self.parent().one()
            return generic_power(self, n, self.parent().one())

        def _pow_naive(self, n):
            r"""
            Return ``self`` to the `n^{th}` power (naive implementation).

            INPUT:

            - ``n`` -- a nonnegative integer

            This naive implementation does not use binary
            exponentiation; there are cases where this is actually
            faster due to size explosion.

            EXAMPLES::

                sage: S = Monoids().example()
                sage: x = S("aa")
                sage: [x._pow_naive(i) for i in range(6)]
                ['', 'aa', 'aaaa', 'aaaaaa', 'aaaaaaaa', 'aaaaaaaaaa']
            """
            if not n:
                return self.parent().one()
            result = self
            for i in range(n - 1):
                result *= self
            return result

        def powers(self, n):
            r"""
            Return the list `[x^0, x^1, \ldots, x^{n-1}]`.

            EXAMPLES::

                sage: A = Matrix([[1, 1], [-1, 0]])
                sage: A.powers(6)
                [
                [1 0]  [ 1  1]  [ 0  1]  [-1  0]  [-1 -1]  [ 0 -1]
                [0 1], [-1  0], [-1 -1], [ 0 -1], [ 1  0], [ 1  1]
                ]
            """
            if n < 0:
                raise ValueError("negative number of powers requested")
            elif n == 0:
                return []
            x = self.parent().one()
            l = [x]
            for i in range(n - 1):
                x = x * self
                l.append(x)
            return l

    class Commutative(CategoryWithAxiom):
        """
        Category of commutative (abelian) monoids.

        A monoid `M` is *commutative* if `xy = yx` for all `x,y \in M`.
        """
        @staticmethod
        def free(index_set=None, names=None, **kwds):
            r"""
            Return a free abelian monoid on `n` generators or with
            the generators indexed by a set `I`.

            A free monoid is constructed by specifing either:

            - the number of generators and/or the names of the generators, or
            - the indexing set for the generators.

            INPUT:

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

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

            EXAMPLES::

                sage: Monoids.Commutative.free(index_set=ZZ)
                Free abelian monoid indexed by Integer Ring
                sage: Monoids().Commutative().free(ZZ)
                Free abelian monoid indexed by Integer Ring
                sage: F.<x,y,z> = Monoids().Commutative().free(); F
                Free abelian monoid indexed by {'x', 'y', 'z'}
            """
            if names is not None:
                if isinstance(names, str):
                    from sage.rings.all import ZZ
                    if ',' not in names and index_set in ZZ:
                        names = [names + repr(i) for i in range(index_set)]
                    else:
                        names = names.split(',')
                names = tuple(names)
                if index_set is None:
                    index_set = names

            from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid
            return IndexedFreeAbelianMonoid(index_set, names=names, **kwds)

    class WithRealizations(WithRealizationsCategory):

        class ParentMethods:

            def one(self):
                r"""
                Return the unit of this monoid.

                This default implementation returns the unit of the
                realization of ``self`` given by
                :meth:`~Sets.WithRealizations.ParentMethods.a_realization`.

                EXAMPLES::

                    sage: A = Sets().WithRealizations().example(); A
                    The subset algebra of {1, 2, 3} over Rational Field
                    sage: A.one.__module__
                    'sage.categories.monoids'
                    sage: A.one()
                    F[{}]

                TESTS::

                    sage: A.one() is A.a_realization().one()
                    True
                    sage: A._test_one()
                """
                return self.a_realization().one()

    class Subquotients(SubquotientsCategory):

        class ParentMethods:

            def one(self):
                """
                Returns the multiplicative unit of this monoid,
                obtained by retracting that of the ambient monoid.

                EXAMPLES::

                    sage: S = Monoids().Subquotients().example() # todo: not implemented
                    sage: S.one()                                # todo: not implemented
                """
                return self.retract(self.ambient().one())

    class Algebras(AlgebrasCategory):

        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Monoids().Algebras(QQ).extra_super_categories()
                [Category of monoids]
                sage: Monoids().Algebras(QQ).super_categories()
                [Category of algebras with basis over Rational Field,
                 Category of semigroup algebras over Rational Field,
                 Category of unital magma algebras over Rational Field]
            """
            return [Monoids()]

        class ParentMethods:

            @cached_method
            def one_basis(self):
                """
                Return the unit of the monoid, which indexes the unit of
                this algebra, as per
                :meth:`AlgebrasWithBasis.ParentMethods.one_basis()
                <sage.categories.algebras_with_basis.AlgebrasWithBasis.ParentMethods.one_basis>`.

                EXAMPLES::

                    sage: A = Monoids().example().algebra(ZZ)
                    sage: A.one_basis()
                    ''
                    sage: A.one()
                    B['']
                    sage: A(3)
                    3*B['']
                """
                return self.basis().keys().one()

            @cached_method
            def algebra_generators(self):
                r"""
                Return generators for this algebra.

                For a monoid algebra, the algebra generators are built
                from the monoid generators if available and from the
                semigroup generators otherwise.

                .. SEEALSO::

                    - :meth:`Semigroups.Algebras.ParentMethods.algebra_generators`
                    - :meth:`MagmaticAlgebras.ParentMethods.algebra_generators()
                      <.magmatic_algebras.MagmaticAlgebras.ParentMethods.algebra_generators>`.

                EXAMPLES::

                    sage: M = Monoids().example(); M
                    An example of a monoid:
                    the free monoid generated by ('a', 'b', 'c', 'd')
                    sage: M.monoid_generators()
                    Finite family {'a': 'a', 'c': 'c', 'b': 'b', 'd': 'd'}
                    sage: M.algebra(ZZ).algebra_generators()
                    Finite family {'a': B['a'], 'c': B['c'], 'b': B['b'], 'd': B['d']}

                    sage: Z12 = Monoids().Finite().example(); Z12
                    An example of a finite multiplicative monoid:
                    the integers modulo 12
                    sage: Z12.monoid_generators()
                    Traceback (most recent call last):
                    ...
                    AttributeError: 'IntegerModMonoid_with_category' object
                    has no attribute 'monoid_generators'
                    sage: Z12.semigroup_generators()
                    Family (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
                    sage: Z12.algebra(QQ).algebra_generators()
                    Finite family {0: B[0], 1: B[1], 2: B[2], 3: B[3],  4: B[4],   5: B[5],
                                   6: B[6], 7: B[7], 8: B[8], 9: B[9], 10: B[10], 11: B[11]}
                """
                monoid = self.basis().keys()
                try:
                    generators = monoid.monoid_generators()
                except AttributeError:
                    generators = monoid.semigroup_generators()
                return generators.map(self.monomial)

        class ElementMethods:

            def is_central(self):
                r"""
                Return whether the element ``self`` is central.

                EXAMPLES::

                    sage: SG4=SymmetricGroupAlgebra(ZZ,4)
                    sage: SG4(1).is_central()
                    True
                    sage: SG4(Permutation([1,3,2,4])).is_central()
                    False
                    sage: A=GroupAlgebras(QQ).example(); A
                    Group algebra of Dihedral group of order 8 as a permutation group over Rational Field
                    sage: sum(i for i in A.basis()).is_central()
                    True
                """
                return all([i*self == self*i for i in self.parent().algebra_generators()])

    class CartesianProducts(CartesianProductsCategory):
        """
        The category of monoids constructed as Cartesian products of monoids.

        This construction gives the direct product of monoids. See
        :wikipedia:`Direct_product` for more information.
        """
        def extra_super_categories(self):
            """
            A Cartesian product of monoids is endowed with a natural
            group structure.

            EXAMPLES::

                sage: C = Monoids().CartesianProducts()
                sage: C.extra_super_categories()
                [Category of monoids]
                sage: sorted(C.super_categories(), key=str)
                [Category of Cartesian products of semigroups,
                 Category of Cartesian products of unital magmas,
                 Category of monoids]
            """
            return [self.base_category()]

        class ParentMethods:
            @cached_method
            def monoid_generators(self):
                """
                Return the generators of ``self``.

                EXAMPLES::

                    sage: M = Monoids.free([1,2,3])
                    sage: N = Monoids.free(['a','b'])
                    sage: C = cartesian_product([M, N])
                    sage: C.monoid_generators()
                    Family ((F[1], 1), (F[2], 1), (F[3], 1),
                            (1, F['a']), (1, F['b']))

                An example with an infinitely generated group (a better output
                is needed)::

                    sage: N = Monoids.free(ZZ)
                    sage: C = cartesian_product([M, N])
                    sage: C.monoid_generators()
                    Lazy family (gen(i))_{i in The Cartesian product of (...)}
                """
                F = self.cartesian_factors()
                ids = tuple(M.one() for M in F)
                def lift(i, gen):
                    cur = list(ids)
                    cur[i] = gen
                    return self._cartesian_product_of_elements(cur)
                from sage.sets.family import Family

                # Finitely generated
                cat = FiniteEnumeratedSets()
                if all(M.monoid_generators() in cat
                       or isinstance(M.monoid_generators(), (tuple, list)) for M in F):
                    ret = [lift(i, gen) for i,M in enumerate(F) for gen in M.monoid_generators()]
                    return Family(ret)

                # Infinitely generated
                # This does not return a good output, but it is "correct"
                # TODO: Figure out a better way to do things
                from sage.categories.cartesian_product import cartesian_product
                gens_prod = cartesian_product([Family(M.monoid_generators(),
                                                      lambda g: (i, g))
                                               for i,M in enumerate(F)])
                return Family(gens_prod, lift, name="gen")
Ejemplo n.º 22
0
class LieAlgebras(Category_over_base_ring):
    """
    The category of Lie algebras.

    EXAMPLES::

        sage: C = LieAlgebras(QQ); C
        Category of Lie algebras over Rational Field
        sage: sorted(C.super_categories(), key=str)
        [Category of vector spaces over Rational Field]

    We construct a typical parent in this category, and do some
    computations with it::

        sage: A = C.example(); A
        An example of a Lie algebra: the Lie algebra from the associative
         algebra Symmetric group algebra of order 3 over Rational Field
         generated by ([2, 1, 3], [2, 3, 1])

        sage: A.category()
        Category of Lie algebras over Rational Field

        sage: A.base_ring()
        Rational Field

        sage: a,b = A.lie_algebra_generators()
        sage: a.bracket(b)
        -[1, 3, 2] + [3, 2, 1]
        sage: b.bracket(2*a + b)
        2*[1, 3, 2] - 2*[3, 2, 1]

        sage: A.bracket(a, b)
        -[1, 3, 2] + [3, 2, 1]

    Please see the source code of `A` (with ``A??``) for how to
    implement other Lie algebras.

    TESTS::

        sage: C = LieAlgebras(QQ)
        sage: TestSuite(C).run()
        sage: TestSuite(C.example()).run()

    .. TODO::

        Many of these tests should use Lie algebras that are not the minimal
        example and need to be added after :trac:`16820` (and :trac:`16823`).
    """
    @cached_method
    def super_categories(self):
        """
        EXAMPLES::

            sage: LieAlgebras(QQ).super_categories()
            [Category of vector spaces over Rational Field]
        """
        # We do not also derive from (Magmatic) algebras since we don't want *
        #   to be our Lie bracket
        # Also this doesn't inherit the ability to add axioms like Associative
        #   and Unital, both of which do not make sense for Lie algebras
        return [Modules(self.base_ring())]

    class SubcategoryMethods:
        def Nilpotent(self):
            r"""
            Return the full subcategory of nilpotent objects of ``self``.

            A Lie algebra `L` is nilpotent if there exist an integer `s` such
            that all iterated brackets of `L` of length more than `s` vanish.
            The integer `s` is called the nilpotency step.
            For instance any abelian Lie algebra is nilpotent of step 1.

            EXAMPLES::

                sage: LieAlgebras(QQ).Nilpotent()
                Category of nilpotent Lie algebras over Rational Field
                sage: LieAlgebras(QQ).WithBasis().Nilpotent()
                Category of nilpotent lie algebras with basis over Rational Field
            """
            return self._with_axiom("Nilpotent")

    Graded = LazyImport('sage.categories.graded_lie_algebras',
                        'GradedLieAlgebras',
                        as_name='Graded')

    # TODO: Find some way to do this without copying most of the logic.
    def _repr_object_names(self):
        r"""
        Return the name of the objects of this category.

        .. SEEALSO:: :meth:`Category._repr_object_names`

        EXAMPLES::

            sage: LieAlgebras(QQ)._repr_object_names()
            'Lie algebras over Rational Field'
            sage: LieAlgebras(Fields())._repr_object_names()
            'Lie algebras over fields'
            sage: from sage.categories.category import JoinCategory
            sage: from sage.categories.category_with_axiom import Blahs
            sage: LieAlgebras(JoinCategory((Blahs().Flying(), Fields())))
            Category of Lie algebras over (flying unital blahs and fields)
        """
        base = self.base()
        if isinstance(base, Category):
            if isinstance(base, JoinCategory):
                name = '(' + ' and '.join(
                    C._repr_object_names()
                    for C in base.super_categories()) + ')'
            else:
                name = base._repr_object_names()
        else:
            name = base
        return "Lie algebras over {}".format(name)

    def example(self, gens=None):
        """
        Return an example of a Lie algebra as per
        :meth:`Category.example <sage.categories.category.Category.example>`.

        EXAMPLES::

            sage: LieAlgebras(QQ).example()
            An example of a Lie algebra: the Lie algebra from the associative algebra
             Symmetric group algebra of order 3 over Rational Field
             generated by ([2, 1, 3], [2, 3, 1])

        Another set of generators can be specified as an optional argument::

            sage: F.<x,y,z> = FreeAlgebra(QQ)
            sage: LieAlgebras(QQ).example(F.gens())
            An example of a Lie algebra: the Lie algebra from the associative algebra
             Free Algebra on 3 generators (x, y, z) over Rational Field
             generated by (x, y, z)
        """
        if gens is None:
            from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
            from sage.rings.all import QQ
            gens = SymmetricGroupAlgebra(QQ, 3).algebra_generators()
        from sage.categories.examples.lie_algebras import Example
        return Example(gens)

    WithBasis = LazyImport('sage.categories.lie_algebras_with_basis',
                           'LieAlgebrasWithBasis',
                           as_name='WithBasis')

    class FiniteDimensional(CategoryWithAxiom_over_base_ring):
        WithBasis = LazyImport(
            'sage.categories.finite_dimensional_lie_algebras_with_basis',
            'FiniteDimensionalLieAlgebrasWithBasis',
            as_name='WithBasis')

        def extra_super_categories(self):
            """
            Implements the fact that a finite dimensional Lie algebra over
            a finite ring is finite.

            EXAMPLES::

                sage: LieAlgebras(IntegerModRing(4)).FiniteDimensional().extra_super_categories()
                [Category of finite sets]
                sage: LieAlgebras(ZZ).FiniteDimensional().extra_super_categories()
                []
                sage: LieAlgebras(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite())
                True
                sage: LieAlgebras(ZZ).FiniteDimensional().is_subcategory(Sets().Finite())
                False
                sage: LieAlgebras(GF(5)).WithBasis().FiniteDimensional().is_subcategory(Sets().Finite())
                True
            """
            if self.base_ring() in Sets().Finite():
                return [Sets().Finite()]
            return []

    class Nilpotent(CategoryWithAxiom_over_base_ring):
        r"""
        Category of nilpotent Lie algebras.

        TESTS::

            sage: C = LieAlgebras(QQ).Nilpotent()
            sage: TestSuite(C).run()
        """
        class ParentMethods:
            @abstract_method
            def step(self):
                r"""
                Return the nilpotency step of ``self``.

                EXAMPLES::

                    sage: h = lie_algebras.Heisenberg(ZZ, oo)
                    sage: h.step()
                    2
                """

            def is_nilpotent(self):
                r"""
                Return ``True`` since ``self`` is nilpotent.

                EXAMPLES::

                    sage: h = lie_algebras.Heisenberg(ZZ, oo)
                    sage: h.is_nilpotent()
                    True
                """
                return True

    class ParentMethods:
        #@abstract_method
        #def lie_algebra_generators(self):
        #    """
        #    Return the generators of ``self`` as a Lie algebra.
        #    """

        # TODO: Move this to LieAlgebraElement, cythonize, and use more standard
        #   coercion framework test (i.e., have_same_parent)
        def bracket(self, lhs, rhs):
            """
            Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and
            ``rhs`` into elements of ``self``.

            If ``lhs`` and ``rhs`` are Lie algebras, then this constructs
            the product space, and if only one of them is a Lie algebra,
            then it constructs the corresponding ideal.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.bracket(x, x + y)
                -[1, 3, 2] + [3, 2, 1]
                sage: L.bracket(x, 0)
                0
                sage: L.bracket(0, x)
                0

            Constructing the product space::

                sage: L = lie_algebras.Heisenberg(QQ, 1)
                sage: Z = L.bracket(L, L); Z
                Ideal (z) of Heisenberg algebra of rank 1 over Rational Field
                sage: L.bracket(L, Z)
                Ideal () of Heisenberg algebra of rank 1 over Rational Field

            Constructing ideals::

                sage: p,q,z = L.basis(); (p,q,z)
                (p1, q1, z)
                sage: L.bracket(3*p, L)
                Ideal (3*p1) of Heisenberg algebra of rank 1 over Rational Field
                sage: L.bracket(L, q+p)
                Ideal (p1 + q1) of Heisenberg algebra of rank 1 over Rational Field
            """
            if lhs in LieAlgebras:
                if rhs in LieAlgebras:
                    return lhs.product_space(rhs)
                return lhs.ideal(rhs)
            elif rhs in LieAlgebras:
                return rhs.ideal(lhs)
            return self(lhs)._bracket_(self(rhs))

        # Do not override this. Instead implement :meth:`_construct_UEA`;
        #   then, :meth:`lift` and :meth:`universal_enveloping_algebra`
        #   will automatically setup the coercion.
        def universal_enveloping_algebra(self):
            """
            Return the universal enveloping algebra of ``self``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.universal_enveloping_algebra()
                Noncommutative Multivariate Polynomial Ring in b0, b1, b2
                 over Rational Field, nc-relations: {}

            ::

                sage: L = LieAlgebra(QQ, 3, 'x', abelian=True)
                sage: L.universal_enveloping_algebra()
                Multivariate Polynomial Ring in x0, x1, x2 over Rational Field

            .. SEEALSO::

                :meth:`lift`
            """
            return self.lift.codomain()

        @abstract_method(optional=True)
        def _construct_UEA(self):
            """
            Return the universal enveloping algebra of ``self``.

            Unlike :meth:`universal_enveloping_algebra`, this method does not
            (usually) construct the canonical lift morphism from ``self``
            to the universal enveloping algebra (let alone register it
            as a coercion).

            One should implement this method and the ``lift`` method for
            the element class to construct the morphism the universal
            enveloping algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L._construct_UEA()
                Noncommutative Multivariate Polynomial Ring in b0, b1, b2
                 over Rational Field, nc-relations: {}

            ::

                sage: L = LieAlgebra(QQ, 3, 'x', abelian=True)
                sage: L.universal_enveloping_algebra() # indirect doctest
                Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
            """

        @abstract_method(optional=True)
        def module(self):
            r"""
            Return an `R`-module which is isomorphic to the
            underlying `R`-module of ``self``.

            The rationale behind this method is to enable linear
            algebraic functionality on ``self`` (such as
            computing the span of a list of vectors in ``self``)
            via an isomorphism from ``self`` to an `R`-module
            (typically, although not always, an `R`-module of
            the form `R^n` for an `n \in \NN`) on which such
            functionality already exists. For this method to be
            of any use, it should return an `R`-module which has
            linear algebraic functionality that ``self`` does
            not have.

            For instance, if ``self`` has ordered basis
            `(e, f, h)`, then ``self.module()`` will be the
            `R`-module `R^3`, and the elements `e`, `f` and
            `h` of ``self`` will correspond to the basis
            vectors `(1, 0, 0)`, `(0, 1, 0)` and `(0, 0, 1)`
            of ``self.module()``.

            This method :meth:`module` needs to be set whenever
            a finite-dimensional Lie algebra with basis is
            intended to support linear algebra (which is, e.g.,
            used in the computation of centralizers and lower
            central series). One then needs to also implement
            the `R`-module isomorphism from ``self`` to
            ``self.module()`` in both directions; that is,
            implement:

            * a ``to_vector`` ElementMethod which sends every
              element of ``self`` to the corresponding element of
              ``self.module()``;

            * a ``from_vector`` ParentMethod which sends every
              element of ``self.module()`` to an element
              of ``self``.

            The ``from_vector`` method will automatically serve
            as an element constructor of ``self`` (that is,
            ``self(v)`` for any ``v`` in ``self.module()`` will
            return ``self.from_vector(v)``).

            .. TODO::

                Ensure that this is actually so.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.module()
                Vector space of dimension 3 over Rational Field
            """

        @abstract_method(optional=True)
        def from_vector(self, v):
            """
            Return the element of ``self`` corresponding to the
            vector ``v`` in ``self.module()``.

            Implement this if you implement :meth:`module`; see the
            documentation of the latter for how this is to be done.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u
                (1, 0, 0)
                sage: parent(u) is L
                True
            """

        @lazy_attribute
        def lift(self):
            r"""
            Construct the lift morphism from ``self`` to the universal
            enveloping algebra of ``self`` (the latter is implemented
            as :meth:`universal_enveloping_algebra`).

            This is a Lie algebra homomorphism. It is injective if
            ``self`` is a free module over its base ring, or if the
            base ring is a `\QQ`-algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: lifted = L.lift(2*a + b - c); lifted
                2*b0 + b1 - b2
                sage: lifted.parent() is L.universal_enveloping_algebra()
                True
            """
            M = LiftMorphism(self, self._construct_UEA())
            M.register_as_coercion()
            return M

        def subalgebra(self, gens, names=None, index_set=None, category=None):
            r"""
            Return the subalgebra of ``self`` generated by ``gens``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.subalgebra([2*a - c, b + c])
                An example of a finite dimensional Lie algebra with basis:
                 the 2-dimensional abelian Lie algebra over Rational Field
                 with basis matrix:
                [   1    0 -1/2]
                [   0    1    1]

            ::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.subalgebra([x + y])
                Traceback (most recent call last):
                ...
                NotImplementedError: subalgebras not yet implemented: see #17416
            """
            raise NotImplementedError(
                "subalgebras not yet implemented: see #17416")
            #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra
            #return LieSubalgebra(gens, names, index_set, category)

        def ideal(self, *gens, **kwds):
            r"""
            Return the ideal of ``self`` generated by ``gens``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.ideal([2*a - c, b + c])
                An example of a finite dimensional Lie algebra with basis:
                 the 2-dimensional abelian Lie algebra over Rational Field
                 with basis matrix:
                [   1    0 -1/2]
                [   0    1    1]

            ::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L.ideal([x + y])
                Traceback (most recent call last):
                ...
                NotImplementedError: ideals not yet implemented: see #16824
            """
            raise NotImplementedError("ideals not yet implemented: see #16824")
            #from sage.algebras.lie_algebras.ideal import LieIdeal
            #if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
            #    gens = gens[0]
            #names = kwds.pop("names", None)
            #index_set = kwds.pop("index_set", None)
            #category = kwds.pop("category", None)
            #return LieIdeal(gens, names, index_set, category)

        def is_ideal(self, A):
            """
            Return if ``self`` is an ideal of ``A``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_ideal(L)
                True
            """
            if A == self:
                return True
            raise NotImplementedError("ideals not yet implemented: see #16824")
            #from sage.algebras.lie_algebras.ideal import LieIdeal
            #return isinstance(self, LieIdeal) and self._ambient is A

        @abstract_method(optional=True)
        def killing_form(self, x, y):
            """
            Return the Killing form of ``x`` and ``y``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: L.killing_form(a, b+c)
                0
            """

        def is_abelian(self):
            r"""
            Return ``True`` if this Lie algebra is abelian.

            A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all
            `x, y \in \mathfrak{g}`.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_abelian()
                False
                sage: R = QQ['x,y']
                sage: L = LieAlgebras(QQ).example(R.gens())
                sage: L.is_abelian()
                True

            ::

                sage: L.<x> = LieAlgebra(QQ,1)  # todo: not implemented - #16823
                sage: L.is_abelian()  # todo: not implemented - #16823
                True
                sage: L.<x,y> = LieAlgebra(QQ,2)  # todo: not implemented - #16823
                sage: L.is_abelian()  # todo: not implemented - #16823
                False
            """
            G = self.lie_algebra_generators()
            if G not in FiniteEnumeratedSets():
                raise NotImplementedError("infinite number of generators")
            zero = self.zero()
            return all(x._bracket_(y) == zero for x in G for y in G)

        def is_commutative(self):
            """
            Return if ``self`` is commutative. This is equivalent to ``self``
            being abelian.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: L.is_commutative()
                False

            ::

                sage: L.<x> = LieAlgebra(QQ, 1) # todo: not implemented - #16823
                sage: L.is_commutative() # todo: not implemented - #16823
                True
            """
            return self.is_abelian()

        @abstract_method(optional=True)
        def is_solvable(self):
            """
            Return if ``self`` is a solvable Lie algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.is_solvable()
                True
            """

        @abstract_method(optional=True)
        def is_nilpotent(self):
            """
            Return if ``self`` is a nilpotent Lie algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: L.is_nilpotent()
                True
            """

        def bch(self, X, Y, prec=None):
            r"""
            Return the element `\log(\exp(X)\exp(Y))`.

            The BCH formula is an expression for `\log(\exp(X)\exp(Y))`
            as a sum of Lie brackets of ``X ` and ``Y`` with rational
            coefficients. It is only defined if the base ring of
            ``self`` has a coercion from the rationals.

            INPUT:

            - ``X`` -- an element of ``self``
            - ``Y`` -- an element of ``self``
            - ``prec`` -- an integer; the maximum length of Lie brackets to be
              considered in the formula

            EXAMPLES:

            The BCH formula for the generators of a free nilpotent Lie
            algebra of step 4::

                sage: L = LieAlgebra(QQ, 2, step=4)
                sage: L.inject_variables()
                Defining X_1, X_2, X_12, X_112, X_122, X_1112, X_1122, X_1222
                sage: L.bch(X_1, X_2)
                X_1 + X_2 + 1/2*X_12 + 1/12*X_112 + 1/12*X_122 + 1/24*X_1122

            An example of the BCH formula in a quotient::

                sage: Q = L.quotient(X_112 + X_122)
                sage: x, y = Q.basis().list()[:2]
                sage: Q.bch(x, y)
                X_1 + X_2 + 1/2*X_12 - 1/24*X_1112

            The BCH formula for a non-nilpotent Lie algebra requires the
            precision to be explicitly stated::

                sage: L.<X,Y> = LieAlgebra(QQ)
                sage: L.bch(X, Y)
                Traceback (most recent call last):
                ...
                ValueError: the Lie algebra is not known to be nilpotent, so you must specify the precision
                sage: L.bch(X, Y, 4)
                X + 1/12*[X, [X, Y]] + 1/24*[X, [[X, Y], Y]] + 1/2*[X, Y] + 1/12*[[X, Y], Y] + Y

            The BCH formula requires a coercion from the rationals::

                sage: L.<X,Y,Z> = LieAlgebra(ZZ, 2, step=2)
                sage: L.bch(X, Y)
                Traceback (most recent call last):
                ...
                TypeError: the BCH formula is not well defined since Integer Ring has no coercion from Rational Field
            """
            if self not in LieAlgebras.Nilpotent and prec is None:
                raise ValueError(
                    "the Lie algebra is not known to be nilpotent,"
                    " so you must specify the precision")
            from sage.algebras.lie_algebras.bch import bch_iterator
            if prec is None:
                return self.sum(Z for Z in bch_iterator(X, Y))
            bch = bch_iterator(X, Y)
            return self.sum(next(bch) for k in range(prec))

        baker_campbell_hausdorff = bch

        @abstract_method(optional=True)
        def lie_group(self, name='G', **kwds):
            r"""
            Return the simply connected Lie group related to ``self``.

            INPUT:

            - ``name`` -- string (default: ``'G'``);
              the name (symbol) given to the Lie group

            EXAMPLES::

                sage: L = lie_algebras.Heisenberg(QQ, 1)
                sage: G = L.lie_group('G'); G
                Lie group G of Heisenberg algebra of rank 1 over Rational Field
            """

        def _test_jacobi_identity(self, **options):
            """
            Test that the Jacobi identity is satisfied on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_jacobi_identity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L._test_jacobi_identity(elements=[x+y, x, 2*y, x.bracket(y)])

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            elts = tester.some_elements()
            jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \
                self.bracket(y, self.bracket(z, x)) + \
                self.bracket(z, self.bracket(x, y))
            zero = self.zero()
            for x in elts:
                for y in elts:
                    if x == y:
                        continue
                    for z in elts:
                        tester.assertEqual(jacobi(x, y, z), zero)

        def _test_antisymmetry(self, **options):
            """
            Test that the antisymmetry axiom is satisfied on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_antisymmetry()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: L._test_antisymmetry(elements=[x+y, x, 2*y, x.bracket(y)])

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            elts = tester.some_elements()
            zero = self.zero()
            for x in elts:
                tester.assertEqual(self.bracket(x, x), zero)

        def _test_distributivity(self, **options):
            r"""
            Test the distributivity of the Lie bracket `[,]` on `+` on (not
            necessarily all) elements of this set.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`.

            TESTS::

                sage: L = LieAlgebras(QQ).example()
                sage: L._test_distributivity()

            EXAMPLES:

            By default, this method runs the tests only on the
            elements returned by ``self.some_elements()``::

                sage: L = LieAlgebra(QQ, 3, 'x,y,z', representation="polynomial")
                sage: L.some_elements()
                [x + y + z]
                sage: L._test_distributivity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # todo: not implemented - #16821
                sage: h1 = L.gen(0) # todo: not implemented - #16821
                sage: h2 = L.gen(1) # todo: not implemented - #16821
                sage: e2 = L.gen(3) # todo: not implemented - #16821
                sage: L._test_distributivity(elements=[h1, h2, e2]) # todo: not implemented - #16821

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            S = tester.some_elements()
            from sage.misc.misc import some_tuples
            for x, y, z in some_tuples(S, 3, tester._max_runs):
                # left distributivity
                tester.assertEqual(self.bracket(x, (y + z)),
                                   self.bracket(x, y) + self.bracket(x, z))
                # right distributivity
                tester.assertEqual(self.bracket((x + y), z),
                                   self.bracket(x, z) + self.bracket(y, z))

    class ElementMethods:
        @coerce_binop
        def bracket(self, rhs):
            """
            Return the Lie bracket ``[self, rhs]``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: x.bracket(y)
                -[1, 3, 2] + [3, 2, 1]
                sage: x.bracket(0)
                0
            """
            return self._bracket_(rhs)

        # Implement this method to define the Lie bracket. You do not
        # need to deal with the coercions here.
        @abstract_method
        def _bracket_(self, y):
            """
            Return the Lie bracket ``[self, y]``, where ``y`` is an
            element of the same Lie algebra as ``self``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).example()
                sage: x,y = L.lie_algebra_generators()
                sage: x._bracket_(y)
                -[1, 3, 2] + [3, 2, 1]
                sage: y._bracket_(x)
                [1, 3, 2] - [3, 2, 1]
                sage: x._bracket_(x)
                0
            """

        @abstract_method(optional=True)
        def to_vector(self):
            """
            Return the vector in ``g.module()`` corresponding to the
            element ``self`` of ``g`` (where ``g`` is the parent of
            ``self``).

            Implement this if you implement ``g.module()``.
            See :meth:`LieAlgebras.module` for how this is to be done.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: u = L((1, 0, 0)).to_vector(); u
                (1, 0, 0)
                sage: parent(u)
                Vector space of dimension 3 over Rational Field
            """

        @abstract_method(optional=True)
        def lift(self):
            """
            Return the image of ``self`` under the canonical lift from the Lie
            algebra to its universal enveloping algebra.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: elt = 3*a + b - c
                sage: elt.lift()
                3*b0 + b1 - b2

            ::

                sage: L.<x,y> = LieAlgebra(QQ, abelian=True)
                sage: x.lift()
                x
            """

        def killing_form(self, x):
            """
            Return the Killing form of ``self`` and ``x``.

            EXAMPLES::

                sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example()
                sage: a, b, c = L.lie_algebra_generators()
                sage: a.killing_form(b)
                0
            """
            return self.parent().killing_form(self, x)

        def exp(self, lie_group=None):
            r"""
            Return the exponential of ``self`` in ``lie_group``.

            INPUT:

            - ``lie_group`` -- (optional) the Lie group to map into;
              If ``lie_group`` is not given, the Lie group associated to the
              parent Lie algebra of ``self`` is used.

            EXAMPLES::

                sage: L.<X,Y,Z> = LieAlgebra(QQ, 2, step=2)
                sage: g = (X + Y + Z).exp(); g
                exp(X + Y + Z)
                sage: h = X.exp(); h
                exp(X)
                sage: g.parent()
                Lie group G of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) over Rational Field
                sage: g.parent() is h.parent()
                True

            The Lie group can be specified explicitly::

                sage: H = L.lie_group('H')
                sage: k = Z.exp(lie_group=H); k
                exp(Z)
                sage: k.parent()
                Lie group H of Free Nilpotent Lie algebra on 3 generators (X, Y, Z) over Rational Field
                sage: g.parent() == k.parent()
                False
            """
            if lie_group is None:
                lie_group = self.parent().lie_group()
            return lie_group.exp(self)
class MagmaticAlgebras(Category_over_base_ring):
    """
    The category of algebras over a given base ring.

    An algebra over a ring `R` is a module over `R` endowed with a
    bilinear multiplication.

    .. WARNING::

        :class:`MagmaticAlgebras` will eventually replace the current
        :class:`Algebras` for consistency with
        e.g. :wikipedia:`Algebras` which assumes neither associativity
        nor the existence of a unit (see :trac:`15043`).

    EXAMPLES::

        sage: from sage.categories.magmatic_algebras import MagmaticAlgebras
        sage: C = MagmaticAlgebras(ZZ); C
        Category of magmatic algebras over Integer Ring
        sage: C.super_categories()
        [Category of additive commutative additive associative additive unital distributive magmas and additive magmas,
         Category of modules over Integer Ring]

    TESTS::

        sage: TestSuite(C).run()
    """
    @cached_method
    def super_categories(self):
        """
        EXAMPLES::

            sage: from sage.categories.magmatic_algebras import MagmaticAlgebras
            sage: MagmaticAlgebras(ZZ).super_categories()
            [Category of additive commutative additive associative additive unital distributive magmas and additive magmas, Category of modules over Integer Ring]

            sage: from sage.categories.additive_semigroups import AdditiveSemigroups
            sage: MagmaticAlgebras(ZZ).is_subcategory((AdditiveSemigroups() & Magmas()).Distributive())
            True

        """
        R = self.base_ring()
        # Note: The specifications impose `self` to be a subcategory
        # of the join of its super categories. Here the join is non
        # trivial, since some of the axioms of Modules (like the
        # commutativity of '+') are added to the left hand side.  We
        # might want the infrastructure to take this join for us.
        return Category.join([(Magmas() & AdditiveMagmas()).Distributive(),
                              Modules(R)],
                             as_list=True)

    Associative = LazyImport('sage.categories.associative_algebras',
                             'AssociativeAlgebras',
                             at_startup=True)
    Unital = LazyImport('sage.categories.unital_algebras',
                        'UnitalAlgebras',
                        at_startup=True)

    class ParentMethods:
        @abstract_method(optional=True)
        def algebra_generators(self):
            """
            Return a family of generators of this algebra.

            EXAMPLES::

                sage: F = AlgebrasWithBasis(QQ).example(); F
                An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                sage: F.algebra_generators()
                Family (B[word: a], B[word: b], B[word: c])
            """

    class WithBasis(CategoryWithAxiom_over_base_ring):
        class ParentMethods:
            @abstract_method(optional=True)
            def product_on_basis(self, i, j):
                """
                The product of the algebra on the basis (optional).

                INPUT:

                - ``i``, ``j`` -- the indices of two elements of the
                  basis of ``self``

                Return the product of the two corresponding basis elements
                indexed by ``i`` and ``j``.

                If implemented, :meth:`product` is defined from
                it by bilinearity.

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example()
                    sage: Word = A.basis().keys()
                    sage: A.product_on_basis(Word("abc"),Word("cba"))
                    B[word: abccba]
                """

            @lazy_attribute
            def product(self):
                """
                The product of the algebra, as per
                :meth:`Magmas.ParentMethods.product()
                <sage.categories.magmas.Magmas.ParentMethods.product>`

                By default, this is implemented using one of the following
                methods, in the specified order:

                - :meth:`.product_on_basis`
                - :meth:`._multiply` or :meth:`._multiply_basis`
                - :meth:`.product_by_coercion`

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example()
                    sage: a, b, c = A.algebra_generators()
                    sage: A.product(a + 2*b, 3*c)
                    3*B[word: ac] + 6*B[word: bc]
                """
                if self.product_on_basis is not NotImplemented:
                    return self._product_from_product_on_basis_multiply

    #                return self._module_morphism(self._module_morphism(self.product_on_basis, position = 0, codomain=self),
    #                                                                                          position = 1)
                elif hasattr(self, "_multiply") or hasattr(
                        self, "_multiply_basis"):
                    return self._product_from_combinatorial_algebra_multiply
                elif hasattr(self, "product_by_coercion"):
                    return self.product_by_coercion
                else:
                    return NotImplemented

            # Provides a product using the product_on_basis by calling linear_combination only once
            def _product_from_product_on_basis_multiply(self, left, right):
                r"""
                Computes the product of two elements by extending
                bilinearly the method :meth:`product_on_basis`.

                EXAMPLES::

                    sage: A = AlgebrasWithBasis(QQ).example(); A
                    An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
                    sage: (a,b,c) = A.algebra_generators()
                    sage: A._product_from_product_on_basis_multiply(a*b + 2*c, a - b)
                    B[word: aba] - B[word: abb] + 2*B[word: ca] - 2*B[word: cb]

                """
                return self.linear_combination(
                    (self.product_on_basis(mon_left, mon_right),
                     coeff_left * coeff_right)
                    for (mon_left, coeff_left
                         ) in left.monomial_coefficients().iteritems()
                    for (mon_right, coeff_right
                         ) in right.monomial_coefficients().iteritems())
Ejemplo n.º 24
0
class AdditiveSemigroups(CategoryWithAxiom_singleton):
    """
    The category of additive semigroups.

    An *additive semigroup* is an associative :class:`additive magma
    <AdditiveMagmas>`, that is a set endowed with an operation `+`
    which is associative.

    EXAMPLES::

        sage: from sage.categories.additive_semigroups import AdditiveSemigroups
        sage: C = AdditiveSemigroups(); C
        Category of additive semigroups
        sage: C.super_categories()
        [Category of additive magmas]
        sage: C.all_super_categories()
        [Category of additive semigroups,
         Category of additive magmas,
         Category of sets,
         Category of sets with partial maps,
         Category of objects]

        sage: C.axioms()
        frozenset({'AdditiveAssociative'})
        sage: C is AdditiveMagmas().AdditiveAssociative()
        True

    TESTS::

        sage: TestSuite(C).run()
    """
    _base_category_class_and_axiom = (AdditiveMagmas, "AdditiveAssociative")

    AdditiveCommutative = LazyImport(
        'sage.categories.commutative_additive_semigroups',
        'CommutativeAdditiveSemigroups',
        at_startup=True)
    AdditiveUnital = LazyImport('sage.categories.additive_monoids',
                                'AdditiveMonoids',
                                at_startup=True)

    class ParentMethods:
        def _test_additive_associativity(self, **options):
            r"""
            Test associativity for (not necessarily all) elements of this
            additive semigroup.

            INPUT:

            - ``options`` -- any keyword arguments accepted by :meth:`_tester`

            EXAMPLES:

            By default, this method tests only the elements returned by
            ``self.some_elements()``::

                sage: S = CommutativeAdditiveSemigroups().example()
                sage: S._test_additive_associativity()

            However, the elements tested can be customized with the
            ``elements`` keyword argument::

                sage: (a,b,c,d) = S.additive_semigroup_generators()
                sage: S._test_additive_associativity(elements = (a, b+c, d))

            See the documentation for :class:`TestSuite` for more information.
            """
            tester = self._tester(**options)
            S = tester.some_elements()
            from sage.combinat.cartesian_product import CartesianProduct
            for x, y, z in tester.some_elements(CartesianProduct(S, S, S)):
                tester.assert_((x + y) + z == x + (y + z))

    class Homsets(HomsetsCategory):
        def extra_super_categories(self):
            r"""
            Implement the fact that a homset between two semigroups is a
            semigroup.

            EXAMPLES::

                sage: from sage.categories.additive_semigroups import AdditiveSemigroups
                sage: AdditiveSemigroups().Homsets().extra_super_categories()
                [Category of additive semigroups]
                sage: AdditiveSemigroups().Homsets().super_categories()
                [Category of homsets of additive magmas, Category of additive semigroups]
            """
            return [AdditiveSemigroups()]

    class CartesianProducts(CartesianProductsCategory):
        def extra_super_categories(self):
            """
            Implement the fact that a cartesian product of additive semigroups
            is an additive semigroup.

            EXAMPLES::

                sage: from sage.categories.additive_semigroups import AdditiveSemigroups
                sage: C = AdditiveSemigroups().CartesianProducts()
                sage: C.extra_super_categories()
                [Category of additive semigroups]
                sage: C.axioms()
                frozenset({'AdditiveAssociative'})
            """
            return [AdditiveSemigroups()]

    class Algebras(AlgebrasCategory):
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: from sage.categories.additive_semigroups import AdditiveSemigroups
                sage: AdditiveSemigroups().Algebras(QQ).extra_super_categories()
                [Category of semigroups]
                sage: CommutativeAdditiveSemigroups().Algebras(QQ).super_categories()
                [Category of additive semigroup algebras over Rational Field,
                 Category of additive commutative additive magma algebras over Rational Field]
            """
            from sage.categories.semigroups import Semigroups
            return [Semigroups()]

        class ParentMethods:
            @cached_method
            def algebra_generators(self):
                r"""
                Return the generators of this algebra, as per
                :meth:`MagmaticAlgebras.ParentMethods.algebra_generators()
                <.magmatic_algebras.MagmaticAlgebras.ParentMethods.algebra_generators>`.

                They correspond to the generators of the additive semigroup.

                EXAMPLES::

                    sage: S = CommutativeAdditiveSemigroups().example(); S
                    An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd')
                    sage: A = S.algebra(QQ)
                    sage: A.algebra_generators()
                    Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]}
                """
                return self.basis().keys().additive_semigroup_generators().map(
                    self.monomial)

            def product_on_basis(self, g1, g2):
                r"""
                Product, on basis elements, as per
                :meth:`MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis()
                <sage.categories.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis>`.

                The product of two basis elements is induced by the
                addition of the corresponding elements of the group.

                EXAMPLES::

                    sage: S = CommutativeAdditiveSemigroups().example(); S
                    An example of a commutative monoid: the free commutative monoid generated by ('a', 'b', 'c', 'd')
                    sage: A = S.algebra(QQ)
                    sage: a,b,c,d = A.algebra_generators()
                    sage: a * b + b * d * c
                    B[c + b + d] + B[a + b]
                """
                return self.monomial(g1 + g2)
Ejemplo n.º 25
0
class JTrivialSemigroups:
    Finite = LazyImport(
        'sage_semigroups.categories.finite_j_trivial_semigroups',
        'FiniteJTrivialSemigroups')
Ejemplo n.º 26
0
class Bialgebras(Category_over_base_ring):
    """
    The category of bialgebras

    EXAMPLES::

        sage: Bialgebras(ZZ)
        Category of bialgebras over Integer Ring
        sage: Bialgebras(ZZ).super_categories()
        [Category of algebras over Integer Ring, Category of coalgebras over Integer Ring]

    TESTS::

        sage: TestSuite(Bialgebras(ZZ)).run()
    """
    def super_categories(self):
        """
        EXAMPLES::

            sage: Bialgebras(QQ).super_categories()
            [Category of algebras over Rational Field, Category of coalgebras over Rational Field]
        """
        R = self.base_ring()
        return [Algebras(R), Coalgebras(R)]

    def additional_structure(self):
        r"""
        Return ``None``.

        Indeed, the category of bialgebras defines no additional
        structure: a morphism of coalgebras and of algebras between
        two bialgebras is a bialgebra morphism.

        .. SEEALSO:: :meth:`Category.additional_structure`

        .. TODO:: This category should be a :class:`CategoryWithAxiom`.

        EXAMPLES::

            sage: Bialgebras(QQ).additional_structure()
        """
        return None

    class ElementMethods:
        def is_primitive(self):
            """
            Return whether ``self`` is a primitive element.

            EXAMPLES::

                sage: s = SymmetricFunctions(QQ).schur()
                sage: s([5]).is_primitive()
                False
                sage: p = SymmetricFunctions(QQ).powersum()
                sage: p([5]).is_primitive()
                True
            """
            one = self.parent().one()
            return self.coproduct() == one.tensor(self) + self.tensor(one)

        def is_grouplike(self):
            """
            Return whether ``self`` is a grouplike element.

            EXAMPLES::

                sage: s = SymmetricFunctions(QQ).schur()
                sage: s([5]).is_grouplike()
                False
                sage: s([]).is_grouplike()
                True
            """
            return self.coproduct() == self.tensor(self)

    class Super(SuperModulesCategory):
        pass

    WithBasis = LazyImport('sage.categories.bialgebras_with_basis',
                           'BialgebrasWithBasis')
Ejemplo n.º 27
0
class Coalgebras(Category_over_base_ring):
    """
    The category of coalgebras

    EXAMPLES::

        sage: Coalgebras(QQ)
        Category of coalgebras over Rational Field
        sage: Coalgebras(QQ).super_categories()
        [Category of vector spaces over Rational Field]

    TESTS::

        sage: TestSuite(Coalgebras(ZZ)).run()
    """
    def super_categories(self):
        """
        EXAMPLES::

            sage: Coalgebras(QQ).super_categories()
            [Category of vector spaces over Rational Field]
        """
        return [Modules(self.base_ring())]

    WithBasis = LazyImport('sage.categories.coalgebras_with_basis',
                           'CoalgebrasWithBasis')
    Graded = LazyImport('sage.categories.graded_coalgebras',
                        'GradedCoalgebras')

    class ParentMethods:
        #def __init_add__(self): # The analogue of initDomainAdd
        #    # Will declare the coproduct of self to the coercion mechanism when it exists
        #    pass

        @abstract_method
        def counit(self, x):
            """
            Return the counit of ``x``.

            Eventually, there will be a default implementation,
            delegating to the overloading mechanism and forcing the
            conversion back

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis:
                 the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, A.counit(a)
                (B[(1,2,3)], 1)
                sage: b, A.counit(b)
                (B[(1,3)], 1)

            TODO: implement some tests of the axioms of coalgebras, bialgebras
            and Hopf algebras using the counit.
            """

        @abstract_method
        def coproduct(self, x):
            """
            Return the coproduct of ``x``.

            Eventually, there will be a default implementation,
            delegating to the overloading mechanism and forcing the
            conversion back

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis:
                 the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, A.coproduct(a)
                (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)])
                sage: b, A.coproduct(b)
                (B[(1,3)], B[(1,3)] # B[(1,3)])
            """
            #return self.tensor_square()(overloaded_coproduct(x))

    class ElementMethods:
        def coproduct(self):
            """
            Return the coproduct of ``self``.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis:
                 the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, a.coproduct()
                (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)])
                sage: b, b.coproduct()
                (B[(1,3)], B[(1,3)] # B[(1,3)])
            """
            return self.parent().coproduct(self)

        def counit(self):
            """
            Return the counit of ``self``.

            EXAMPLES::

                sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                An example of Hopf algebra with basis:
                 the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                sage: [a,b] = A.algebra_generators()
                sage: a, a.counit()
                (B[(1,2,3)], 1)
                sage: b, b.counit()
                (B[(1,3)], 1)
            """
            return self.parent().counit(self)

    class SubcategoryMethods:
        @cached_method
        def Cocommutative(self):
            r"""
            Return the full subcategory of the cocommutative objects
            of ``self``.

            A coalgebra `C` is said to be *cocommutative* if

            .. MATH::

                \Delta(c) = \sum_{(c)} c_{(1)} \otimes c_{(2)}
                = \sum_{(c)} c_{(2)} \otimes c_{(1)}

            in Sweedler's notation for all `c \in C`.

            EXAMPLES::

                sage: C1 = Coalgebras(ZZ).Cocommutative().WithBasis(); C1
                Category of cocommutative coalgebras with basis over Integer Ring
                sage: C2 = Coalgebras(ZZ).WithBasis().Cocommutative()
                sage: C1 is C2
                True
                sage: BialgebrasWithBasis(QQ).Cocommutative()
                Category of cocommutative bialgebras with basis over Rational Field

            TESTS::

                sage: TestSuite(Coalgebras(ZZ).Cocommutative()).run()
            """
            return self._with_axiom("Cocommutative")

    class Cocommutative(CategoryWithAxiom_over_base_ring):
        """
        Category of cocommutative coalgebras.
        """

    class TensorProducts(TensorProductsCategory):
        @cached_method
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Coalgebras(QQ).TensorProducts().extra_super_categories()
                [Category of coalgebras over Rational Field]
                sage: Coalgebras(QQ).TensorProducts().super_categories()
                [Category of tensor products of vector spaces over Rational Field,
                 Category of coalgebras over Rational Field]

            Meaning: a tensor product of coalgebras is a coalgebra
            """
            return [self.base_category()]

        class ParentMethods:
            # TODO: provide this default implementation of one if one_basis is not implemented
            #def one(self):
            #    return tensor(module.one() for module in self.modules)
            pass

        class ElementMethods:
            pass

    class DualObjects(DualObjectsCategory):
        def extra_super_categories(self):
            r"""
            Return the dual category.

            EXAMPLES:

            The category of coalgebras over the Rational Field is dual
            to the category of algebras over the same field::

                sage: C = Coalgebras(QQ)
                sage: C.dual()
                Category of duals of coalgebras over Rational Field
                sage: C.dual().super_categories() # indirect doctest
                [Category of algebras over Rational Field,
                 Category of duals of vector spaces over Rational Field]

            .. WARNING::

                This is only correct in certain cases (finite dimension, ...).
                See :trac:`15647`.
            """
            from sage.categories.algebras import Algebras
            return [Algebras(self.base_category().base_ring())]

    class Super(SuperModulesCategory):
        def extra_super_categories(self):
            """
            EXAMPLES::

                sage: Coalgebras(ZZ).Super().extra_super_categories()
                [Category of graded coalgebras over Integer Ring]
                sage: Coalgebras(ZZ).Super().super_categories()
                [Category of graded coalgebras over Integer Ring,
                 Category of super modules over Integer Ring]

            Compare this with the situation for bialgebras::

                sage: Bialgebras(ZZ).Super().extra_super_categories()
                []
                sage: Bialgebras(ZZ).Super().super_categories()
                [Category of super algebras over Integer Ring,
                 Category of super coalgebras over Integer Ring]

            The category of bialgebras does not occur in these results,
            since super bialgebras are not bialgebras.
            """
            return [self.base_category().Graded()]

        class SubcategoryMethods:
            @cached_method
            def Supercocommutative(self):
                r"""
                Return the full subcategory of the supercocommutative
                objects of ``self``.

                EXAMPLES::

                    sage: Coalgebras(ZZ).WithBasis().Super().Supercocommutative()
                    Category of supercocommutative super coalgebras with basis over Integer Ring
                    sage: BialgebrasWithBasis(QQ).Super().Supercocommutative()
                    Join of Category of super algebras with basis over Rational Field
                     and Category of super bialgebras over Rational Field
                     and Category of super coalgebras with basis over Rational Field
                     and Category of supercocommutative super coalgebras over Rational Field

                TESTS::

                    sage: TestSuite(HopfAlgebras(ZZ).Super().Supercocommutative()).run()
                """
                return self._with_axiom("Supercocommutative")

        class Supercocommutative(CategoryWithAxiom_over_base_ring):
            """
            Category of supercocommutative coalgebras.
            """

    class Filtered(FilteredModulesCategory):
        """
        Category of filtered coalgebras.
        """

    class WithRealizations(WithRealizationsCategory):
        class ParentMethods:
            def coproduct(self, x):
                r"""
                Return the coproduct of ``x``.

                EXAMPLES::

                    sage: N = NonCommutativeSymmetricFunctions(QQ)
                    sage: S = N.complete()
                    sage: N.coproduct.__module__
                    'sage.categories.coalgebras'
                    sage: N.coproduct(S[2])
                    S[] # S[2] + S[1] # S[1] + S[2] # S[]
                """
                return self.a_realization()(x).coproduct()

            def counit(self, x):
                r"""
                Return the counit of ``x``.

                EXAMPLES::

                    sage: Sym = SymmetricFunctions(QQ)
                    sage: s = Sym.schur()
                    sage: f = s[2,1]
                    sage: f.counit.__module__
                    'sage.categories.coalgebras'
                    sage: f.counit()
                    0

                ::

                    sage: N = NonCommutativeSymmetricFunctions(QQ)
                    sage: N.counit.__module__
                    'sage.categories.coalgebras'
                    sage: N.counit(N.one())
                    1
                    sage: x = N.an_element(); x
                    2*S[] + 2*S[1] + 3*S[1, 1]
                    sage: N.counit(x)
                    2
                """
                return self.a_realization()(x).counit()

    class Realizations(RealizationsCategory):
        class ParentMethods:
            def coproduct_by_coercion(self, x):
                r"""
                Return the coproduct by coercion if ``coproduct_by_basis``
                is not implemented.

                EXAMPLES::

                    sage: Sym = SymmetricFunctions(QQ)
                    sage: m = Sym.monomial()
                    sage: f = m[2,1]
                    sage: f.coproduct.__module__
                    'sage.categories.coalgebras'
                    sage: m.coproduct_on_basis
                    NotImplemented
                    sage: m.coproduct == m.coproduct_by_coercion
                    True
                    sage: f.coproduct()
                    m[] # m[2, 1] + m[1] # m[2] + m[2] # m[1] + m[2, 1] # m[]

                ::

                    sage: N = NonCommutativeSymmetricFunctions(QQ)
                    sage: R = N.ribbon()
                    sage: R.coproduct_by_coercion.__module__
                    'sage.categories.coalgebras'
                    sage: R.coproduct_on_basis
                    NotImplemented
                    sage: R.coproduct == R.coproduct_by_coercion
                    True
                    sage: R[1].coproduct()
                    R[] # R[1] + R[1] # R[]
                """
                R = self.realization_of().a_realization()
                return self.tensor_square()(R(x).coproduct())

            def counit_by_coercion(self, x):
                r"""
                Return the counit of ``x`` if ``counit_by_basis`` is
                not implemented.

                EXAMPLES::

                    sage: sp = SymmetricFunctions(QQ).sp()
                    sage: sp.an_element()
                    2*sp[] + 2*sp[1] + 3*sp[2]
                    sage: sp.counit(sp.an_element())
                    2

                    sage: o = SymmetricFunctions(QQ).o()
                    sage: o.an_element()
                    2*o[] + 2*o[1] + 3*o[2]
                    sage: o.counit(o.an_element())
                    -1
                """
                R = self.realization_of().a_realization()
                return R(x).counit()
Ejemplo n.º 28
0
class AdditiveGroups(CategoryWithAxiom_singleton):
    r"""
    The category of additive groups.

    An *additive group* is a set with an internal binary operation `+` which
    is associative, admits a zero, and where every element can be negated.

    EXAMPLES::

        sage: from sage.categories.additive_groups import AdditiveGroups
        sage: from sage.categories.additive_monoids import AdditiveMonoids
        sage: AdditiveGroups()
        Category of additive groups
        sage: AdditiveGroups().super_categories()
        [Category of additive inverse additive unital additive magmas,
         Category of additive monoids]
        sage: AdditiveGroups().all_super_categories()
        [Category of additive groups,
         Category of additive inverse additive unital additive magmas,
         Category of additive monoids,
         Category of additive unital additive magmas,
         Category of additive semigroups,
         Category of additive magmas,
         Category of sets,
         Category of sets with partial maps,
         Category of objects]

        sage: AdditiveGroups().axioms()
        frozenset(['AdditiveAssociative', 'AdditiveUnital', 'AdditiveInverse'])
        sage: AdditiveGroups() is AdditiveMonoids().AdditiveInverse()
        True

    TESTS::

        sage: C = AdditiveGroups()
        sage: TestSuite(C).run()
    """
    _base_category_class_and_axiom = (AdditiveMonoids, "AdditiveInverse")

    AdditiveCommutative = LazyImport(
        'sage.categories.commutative_additive_groups',
        'CommutativeAdditiveGroups',
        at_startup=True)

    class ElementMethods:
        ##def -x, -(x,y):
        def __sub__(left, right):
            """
            Top-level subtraction operator.
            See extensive documentation at the top of ``element.pyx``.

            EXAMPLES::

                sage: F = CombinatorialFreeModule(QQ, ['a','b'])
                sage: a,b = F.basis()
                sage: a - b
                B['a'] - B['b']
            """
            if have_same_parent(left, right) and hasattr(left, "_sub_"):
                return left._sub_(right)
            from sage.structure.element import get_coercion_model
            import operator
            return get_coercion_model().bin_op(left, right, operator.sub)

        ##################################################
        # Negation
        ##################################################

        def __neg__(self):
            """
            Top-level negation operator for elements of abelian
            monoids, which may choose to implement ``_neg_`` rather than
            ``__neg__`` for consistancy.

            EXAMPLES::

                sage: F = CombinatorialFreeModule(QQ, ['a','b'])
                sage: a,b = F.basis()
                sage: - b
                -B['b']
            """
            return self._neg_()
Ejemplo n.º 29
0
class Posets(Category):
    r"""
    The category of posets i.e. sets with a partial order structure.

    EXAMPLES::

        sage: Posets()
        Category of posets
        sage: Posets().super_categories()
        [Category of sets]
        sage: P = Posets().example(); P
        An example of a poset: sets ordered by inclusion

    The partial order is implemented by the mandatory method
    :meth:`~Posets.ParentMethods.le`::

        sage: x = P(Set([1,3])); y = P(Set([1,2,3]))
        sage: x, y
        ({1, 3}, {1, 2, 3})
        sage: P.le(x, y)
        True
        sage: P.le(x, x)
        True
        sage: P.le(y, x)
        False

    The other comparison methods are called
    :meth:`~Posets.ParentMethods.lt`, :meth:`~Posets.ParentMethods.ge`,
    :meth:`~Posets.ParentMethods.gt`, following Python's naming
    convention in :mod:`operator`. Default implementations are
    provided::

        sage: P.lt(x, x)
        False
        sage: P.ge(y, x)
        True

    Unless the poset is a facade (see :class:`Sets.Facade`), one can
    compare directly its elements using the usual Python operators::

        sage: D = Poset((divisors(30), attrcall("divides")), facade = False)
        sage: D(3) <= D(6)
        True
        sage: D(3) <= D(3)
        True
        sage: D(3) <= D(5)
        False
        sage: D(3) < D(3)
        False
        sage: D(10) >= D(5)
        True

    At this point, this has to be implemented by hand. Once
    :trac:`10130` will be resolved, this will be automatically
    provided by this category::

        sage: x < y      # todo: not implemented
        True
        sage: x < x      # todo: not implemented
        False
        sage: x <= x     # todo: not implemented
        True
        sage: y >= x     # todo: not implemented
        True

    .. seealso:: :func:`Poset`, :class:`FinitePosets`, :class:`LatticePosets`

    TESTS::

        sage: C = Posets()
        sage: TestSuite(C).run()

    """
    @cached_method
    def super_categories(self):
        r"""
        Return a list of the (immediate) super categories of
        ``self``, as per :meth:`Category.super_categories`.

        EXAMPLES::

            sage: Posets().super_categories()
            [Category of sets]
        """
        return [Sets()]

    def example(self, choice=None):
        r"""
        Return examples of objects of ``Posets()``, as per
        :meth:`Category.example()
        <sage.categories.category.Category.example>`.

        EXAMPLES::

            sage: Posets().example()
            An example of a poset: sets ordered by inclusion

            sage: Posets().example("facade")
            An example of a facade poset: the positive integers ordered by divisibility
        """
        from sage.categories.examples.posets import FiniteSetsOrderedByInclusion, PositiveIntegersOrderedByDivisibilityFacade
        if choice == "facade":
            return PositiveIntegersOrderedByDivisibilityFacade()
        else:
            return FiniteSetsOrderedByInclusion()

    def __iter__(self):
        r"""
        Iterator over representatives of the isomorphism classes of
        posets with finitely many vertices.

        .. warning:: this feature may become deprecated, since it does
           of course not iterate through all posets.

        EXAMPLES::

            sage: P = Posets()
            sage: it = iter(P)
            sage: for _ in range(10): print next(it);
            Finite poset containing 0 elements
            Finite poset containing 1 elements
            Finite poset containing 2 elements
            Finite poset containing 2 elements
            Finite poset containing 3 elements
            Finite poset containing 3 elements
            Finite poset containing 3 elements
            Finite poset containing 3 elements
            Finite poset containing 3 elements
            Finite poset containing 4 elements
        """
        from sage.combinat.posets.posets import FinitePosets_n
        n = 0
        while True:
            for P in FinitePosets_n(n):
                yield P
            n += 1

    Finite = LazyImport('sage.categories.finite_posets', 'FinitePosets')

    class ParentMethods:
        @abstract_method
        def le(self, x, y):
            r"""
            Return whether `x \le y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.le( 3, 6 )
                True
                sage: D.le( 3, 3 )
                True
                sage: D.le( 3, 5 )
                False
            """

        def lt(self, x, y):
            r"""
            Return whether `x < y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`le`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.lt( 3, 6 )
                True
                sage: D.lt( 3, 3 )
                False
                sage: D.lt( 3, 5 )
                False
            """
            return self.le(x, y) and x != y

        def ge(self, x, y):
            r"""
            Return whether `x \ge y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`le`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.ge( 6, 3 )
                True
                sage: D.ge( 3, 3 )
                True
                sage: D.ge( 3, 5 )
                False
            """
            return self.le(y, x)

        def gt(self, x, y):
            r"""
            Return whether `x > y` in the poset ``self``.

            INPUT:

            - ``x``, ``y`` -- elements of ``self``.

            This default implementation delegates the work to :meth:`lt`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.gt( 3, 6 )
                False
                sage: D.gt( 3, 3 )
                False
                sage: D.gt( 3, 5 )
                False
            """
            return self.lt(y, x)

        @abstract_method(optional=True)
        def upper_covers(self, x):
            r"""
            Return the upper covers of `x`, that is, the elements `y`
            such that `x<y` and there exists no `z` such that `x<z<y`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.upper_covers(3)
                [6, 15]
            """

        @abstract_method(optional=True)
        def lower_covers(self, x):
            r"""
            Return the lower covers of `x`, that is, the elements `y`
            such that `y<x` and there exists no `z` such that `y<z<x`.

            EXAMPLES::

                sage: D = Poset((divisors(30), attrcall("divides")))
                sage: D.lower_covers(15)
                [3, 5]
            """

        @abstract_method(optional=True)
        def order_ideal(self, elements):
            r"""
            Return the order ideal in ``self`` generated by the elements
            of an iterable ``elements``.

            A subset `I` of a poset is said to be an order ideal if, for
            any `x` in `I` and `y` such that `y \le x`, then `y` is in `I`.

            This is also called the lower set generated by these elements.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.order_ideal([7,10])
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]
            """

        lower_set = order_ideal

        @abstract_method(optional=True)
        def order_filter(self, elements):
            r"""
            Return the order filter generated by a list of elements.

            A subset `I` of a poset is said to be an order filter if, for
            any `x` in `I` and `y` such that `y \ge x`, then `y` is in `I`.

            This is also called the upper set generated by these elements.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.order_filter([3,8])
                [3, 7, 8, 9, 10, 11, 12, 13, 14, 15]
            """

        upper_set = order_filter

        def directed_subset(self, elements, direction):
            r"""
            Return the order filter or the order ideal generated by a
            list of elements.

            If ``direction`` is 'up', the order filter (upper set) is
            being returned.

            If ``direction`` is 'down', the order ideal (lower set) is
            being returned.

            INPUT:

            - elements -- a list of elements.

            - direction -- 'up' or 'down'.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.directed_subset([3, 8], 'up')
                [3, 7, 8, 9, 10, 11, 12, 13, 14, 15]
                sage: B.directed_subset([7, 10], 'down')
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]
            """
            if direction == 'up':
                return self.order_filter(elements)
            if direction == 'down':
                return self.order_ideal(elements)
            raise ValueError("Direction must be either 'up' or 'down'.")

        def principal_order_ideal(self, x):
            r"""
            Return the order ideal generated by an element ``x``.

            This is also called the lower set generated by this element.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.principal_order_ideal(6)
                [0, 2, 4, 6]
            """
            return self.order_ideal([x])

        principal_lower_set = principal_order_ideal

        def principal_order_filter(self, x):
            r"""
            Return the order filter generated by an element ``x``.

            This is also called the upper set generated by this element.

            EXAMPLES::

                sage: B = Posets.BooleanLattice(4)
                sage: B.principal_order_filter(2)
                [2, 3, 6, 7, 10, 11, 14, 15]
            """
            return self.order_filter([x])

        principal_upper_set = principal_order_filter

        def order_ideal_toggle(self, I, v):
            r"""
            Return the result of toggling the element ``v`` in the
            order ideal ``I``.

            If `v` is an element of a poset `P`, then toggling the
            element `v` is an automorphism of the set `J(P)` of all
            order ideals of `P`. It is defined as follows: If `I`
            is an order ideal of `P`, then the image of `I` under
            toggling the element `v` is

            - the set `I \cup \{ v \}`, if `v \not\in I` but
              every element of `P` smaller than `v` is in `I`;

            - the set `I \setminus \{ v \}`, if `v \in I` but
              no element of `P` greater than `v` is in `I`;

            - `I` otherwise.

            This image always is an order ideal of `P`.

            EXAMPLES::

                sage: P = Poset({1: [2,3], 2: [4], 3: []})
                sage: I = Set({1, 2})
                sage: I in P.order_ideals_lattice()
                True
                sage: P.order_ideal_toggle(I, 1)
                {1, 2}
                sage: P.order_ideal_toggle(I, 2)
                {1}
                sage: P.order_ideal_toggle(I, 3)
                {1, 2, 3}
                sage: P.order_ideal_toggle(I, 4)
                {1, 2, 4}
                sage: P4 = Posets(4)
                sage: all(all(all(P.order_ideal_toggle(P.order_ideal_toggle(I, i), i) == I
                ....:               for i in range(4))
                ....:          for I in P.order_ideals_lattice(facade=True))
                ....:     for P in P4)
                True
            """
            if not v in I:
                if all(u in I for u in self.lower_covers(v)):
                    from sage.sets.set import Set
                    return I.union(Set({v}))
            else:
                if all(u not in I for u in self.upper_covers(v)):
                    from sage.sets.set import Set
                    return I.difference(Set({v}))
            return I

        def order_ideal_toggles(self, I, vs):
            r"""
            Return the result of toggling the elements of the list (or
            iterable) ``vs`` (one by one, from left to right) in the order
            ideal ``I``.

            See :meth:`order_ideal_toggle` for a definition of toggling.

            EXAMPLES::

                sage: P = Poset({1: [2,3], 2: [4], 3: []})
                sage: I = Set({1, 2})
                sage: P.order_ideal_toggles(I, [1,2,3,4])
                {1, 3}
                sage: P.order_ideal_toggles(I, (1,2,3,4))
                {1, 3}
            """
            for v in vs:
                I = self.order_ideal_toggle(I, v)
            return I

        def is_order_ideal(self, o):
            """
            Return whether ``o`` is an order ideal of ``self``, assuming ``self``
            has no infinite descending path.

            INPUT:

            - ``o`` -- a list (or set, or tuple) containing some elements of ``self``

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_order_ideal([1, 3])
                True
                sage: P.is_order_ideal([])
                True
                sage: P.is_order_ideal({1, 3})
                True
                sage: P.is_order_ideal([1, 3, 4])
                False

            """
            return all((u in self and all(x in o
                                          for x in self.lower_covers(u)))
                       for u in o)

        def is_order_filter(self, o):
            """
            Return whether ``o`` is an order filter of ``self``, assuming ``self``
            has no infinite ascending path.

            INPUT:

            - ``o`` -- a list (or set, or tuple) containing some elements of ``self``

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_order_filter([4, 12])
                True
                sage: P.is_order_filter([])
                True
                sage: P.is_order_filter({3, 4, 12})
                False
                sage: P.is_order_filter({3, 6, 12})
                True

            """
            return all((u in self and all(x in o
                                          for x in self.upper_covers(u)))
                       for u in o)

        def is_chain_of_poset(self, o, ordered=False):
            """
            Return whether an iterable ``o`` is a chain of ``self``,
            including a check for ``o`` being ordered from smallest
            to largest element if the keyword ``ordered`` is set to
            ``True``.

            INPUT:

            - ``o`` -- an iterable (e. g., list, set, or tuple)
              containing some elements of ``self``

            - ``ordered`` -- a Boolean (default: ``False``) which
              decides whether the notion of a chain includes being
              ordered

            OUTPUT:

            If ``ordered`` is set to ``False``, the truth value of
            the following assertion is returned: The subset of ``self``
            formed by the elements of ``o`` is a chain in ``self``.

            If ``ordered`` is set to ``True``, the truth value of
            the following assertion is returned: Every element of the
            list ``o`` is (strictly!) smaller than its successor in
            ``self``. (This makes no sense if ``ordered`` is a set.)

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_chain_of_poset([1, 3])
                True
                sage: P.is_chain_of_poset([3, 1])
                True
                sage: P.is_chain_of_poset([1, 3], ordered=True)
                True
                sage: P.is_chain_of_poset([3, 1], ordered=True)
                False
                sage: P.is_chain_of_poset([])
                True
                sage: P.is_chain_of_poset([], ordered=True)
                True
                sage: P.is_chain_of_poset((2, 12, 6))
                True
                sage: P.is_chain_of_poset((2, 6, 12), ordered=True)
                True
                sage: P.is_chain_of_poset((2, 12, 6), ordered=True)
                False
                sage: P.is_chain_of_poset((2, 12, 6, 3))
                False
                sage: P.is_chain_of_poset((2, 3))
                False

                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
                sage: Q.is_chain_of_poset([1, 2], ordered=True)
                False
                sage: Q.is_chain_of_poset([1, 2])
                True
                sage: Q.is_chain_of_poset([2, 1], ordered=True)
                True
                sage: Q.is_chain_of_poset([2, 1, 1], ordered=True)
                False
                sage: Q.is_chain_of_poset([3])
                True
                sage: Q.is_chain_of_poset([4, 2, 3])
                True
                sage: Q.is_chain_of_poset([4, 2, 3], ordered=True)
                False
                sage: Q.is_chain_of_poset([2, 3, 4], ordered=True)
                True

            Examples with infinite posets::

                sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion
                sage: R = FiniteSetsOrderedByInclusion()
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))])
                False
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))], ordered=True)
                False
                sage: R.is_chain_of_poset([R(set([3, 1, 2])), R(set([1, 2])), R(set([1]))])
                True

                sage: from sage.categories.examples.posets import PositiveIntegersOrderedByDivisibilityFacade
                sage: T = PositiveIntegersOrderedByDivisibilityFacade()
                sage: T.is_chain_of_poset((T(3), T(4), T(7)))
                False
                sage: T.is_chain_of_poset((T(3), T(6), T(3)))
                True
                sage: T.is_chain_of_poset((T(3), T(6), T(3)), ordered=True)
                False
                sage: T.is_chain_of_poset((T(3), T(3), T(6)))
                True
                sage: T.is_chain_of_poset((T(3), T(3), T(6)), ordered=True)
                False
                sage: T.is_chain_of_poset((T(3), T(6)), ordered=True)
                True
                sage: T.is_chain_of_poset((), ordered=True)
                True
                sage: T.is_chain_of_poset((T(3),), ordered=True)
                True
                sage: T.is_chain_of_poset((T(q) for q in divisors(27)))
                True
                sage: T.is_chain_of_poset((T(q) for q in divisors(18)))
                False
            """
            list_o = list(o)
            if ordered:
                return all(self.lt(a, b) for a, b in zip(list_o, list_o[1:]))
            else:
                for (i, x) in enumerate(list_o):
                    for y in list_o[:i]:
                        if (not self.le(x, y)) and (not self.gt(x, y)):
                            return False
                return True

        def is_antichain_of_poset(self, o):
            """
            Return whether an iterable ``o`` is an antichain of
            ``self``.

            INPUT:

            - ``o`` -- an iterable (e. g., list, set, or tuple)
              containing some elements of ``self``

            OUTPUT:

            ``True`` if the subset of ``self`` consisting of the entries
            of ``o`` is an antichain of ``self``, and ``False`` otherwise.

            EXAMPLES::

                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
                sage: sorted(P.list())
                [1, 2, 3, 4, 6, 12]
                sage: P.is_antichain_of_poset([1, 3])
                False
                sage: P.is_antichain_of_poset([3, 1])
                False
                sage: P.is_antichain_of_poset([1, 1, 3])
                False
                sage: P.is_antichain_of_poset([])
                True
                sage: P.is_antichain_of_poset([1])
                True
                sage: P.is_antichain_of_poset([1, 1])
                True
                sage: P.is_antichain_of_poset([3, 4])
                True
                sage: P.is_antichain_of_poset([3, 4, 12])
                False
                sage: P.is_antichain_of_poset([6, 4])
                True
                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 < i and i < 6))
                True
                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 <= i and i < 6))
                False

                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
                sage: Q.is_antichain_of_poset((1, 2))
                False
                sage: Q.is_antichain_of_poset((2, 4))
                False
                sage: Q.is_antichain_of_poset((4, 2))
                False
                sage: Q.is_antichain_of_poset((2, 2))
                True
                sage: Q.is_antichain_of_poset((3, 4))
                False
                sage: Q.is_antichain_of_poset((3, 1))
                True
                sage: Q.is_antichain_of_poset((1, ))
                True
                sage: Q.is_antichain_of_poset(())
                True

            An infinite poset::

                sage: from sage.categories.examples.posets import FiniteSetsOrderedByInclusion
                sage: R = FiniteSetsOrderedByInclusion()
                sage: R.is_antichain_of_poset([R(set([3, 1, 2])), R(set([1, 4])), R(set([4, 5]))])
                True
                sage: R.is_antichain_of_poset([R(set([3, 1, 2, 4])), R(set([1, 4])), R(set([4, 5]))])
                False
            """
            return all(not self.lt(x, y) for x in o for y in o)

    class ElementMethods:
        pass
Ejemplo n.º 30
0
class Fields(CategoryWithAxiom):
    """
    The category of (commutative) fields, i.e. commutative rings where
    all non-zero elements have multiplicative inverses

    EXAMPLES::

        sage: K = Fields()
        sage: K
        Category of fields
        sage: Fields().super_categories()
        [Category of euclidean domains, Category of division rings]

        sage: K(IntegerRing())
        Rational Field
        sage: K(PolynomialRing(GF(3), 'x'))
        Fraction Field of Univariate Polynomial Ring in x over
        Finite Field of size 3
        sage: K(RealField())
        Real Field with 53 bits of precision

    TESTS::

        sage: TestSuite(Fields()).run()
    """
    _base_category_class_and_axiom = (DivisionRings, "Commutative")

    def extra_super_categories(self):
        """
        EXAMPLES::

            sage: Fields().extra_super_categories()
            [Category of euclidean domains]

        """
        return [EuclideanDomains()]

    def __contains__(self, x):
        """
        EXAMPLES::

            sage: GF(4, "a") in Fields()
            True
            sage: QQ in Fields()
            True
            sage: ZZ in Fields()
            False
            sage: IntegerModRing(4) in Fields()
            False
            sage: InfinityRing in Fields()
            False

        This implementation will not be needed anymore once every
        field in Sage will be properly declared in the category
        :class:`Fields`().

        Caveat: this should eventually be fixed::

            sage: gap.Rationals in Fields()
            False

        typically by implementing the method :meth:`category`
        appropriately for Gap objects::

            sage: GR = gap.Rationals
            sage: GR.category = lambda : Fields()
            sage: GR in Fields()
            True

        The following tests against a memory leak fixed in :trac:`13370`::

            sage: import gc
            sage: _ = gc.collect()
            sage: n = len([X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)])
            sage: for i in prime_range(100):
            ...     R = ZZ.quotient(i)
            ...     t = R in Fields()
            sage: _ = gc.collect()
            sage: len([X for X in gc.get_objects() if isinstance(X, sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic)]) - n
            1

        """
        try:
            return self._contains_helper(x) or sage.rings.ring._is_Field(x)
        except Exception:
            return False

    @lazy_class_attribute
    def _contains_helper(cls):
        """
        Helper for containment tests in the category of fields.

        This helper just tests whether the given object's category
        is already known to be a sub-category of the category of
        fields. There are, however, rings that are initialised
        as plain commutative rings and found out to be fields
        only afterwards. Hence, this helper alone is not enough
        for a proper containment test.

        TESTS::

            sage: P.<x> = QQ[]
            sage: Q = P.quotient(x^2+2)
            sage: Q.category()
            Join of Category of commutative algebras over Rational Field and Category of subquotients of monoids and Category of quotients of semigroups
            sage: F = Fields()
            sage: F._contains_helper(Q)
            False
            sage: Q in F  # This changes the category!
            True
            sage: F._contains_helper(Q)
            True

        """
        return Category_contains_method_by_parent_class(cls())

    def _call_(self, x):
        """
        Construct a field from the data in ``x``

        EXAMPLES::

            sage: K = Fields()
            sage: K
            Category of fields
            sage: Fields().super_categories()
            [Category of euclidean domains, Category of division rings]

            sage: K(IntegerRing()) # indirect doctest
            Rational Field
            sage: K(PolynomialRing(GF(3), 'x')) # indirect doctest
            Fraction Field of Univariate Polynomial Ring in x over
            Finite Field of size 3
            sage: K(RealField())
            Real Field with 53 bits of precision
        """
        try:
            return x.fraction_field()
        except AttributeError:
            raise TypeError("unable to associate a field to %s"%x)

    Finite = LazyImport('sage.categories.finite_fields', 'FiniteFields', at_startup=True)

    class ParentMethods:

        def is_field( self, proof=True ):
            r"""
            Returns True as ``self`` is a field.

            EXAMPLES::

                sage: QQ.is_field()
                True
                sage: Parent(QQ,category=Fields()).is_field()
                True
            """
            return True

        def is_integrally_closed(self):
            r"""
            Return ``True``, as per :meth:`IntegralDomain.is_integrally_closed`:
            for every field `F`, `F` is its own field of fractions,
            hence every element of `F` is integral over `F`.

            EXAMPLES::

                sage: QQ.is_integrally_closed()
                True
                sage: QQbar.is_integrally_closed()
                True
                sage: Z5 = GF(5); Z5
                Finite Field of size 5
                sage: Z5.is_integrally_closed()
                True
            """
            return True

        def is_perfect(self):
            r"""
            Return whether this field is perfect, i.e., its characteristic is
            `p=0` or every element has a `p`-th root.

            EXAMPLES::

                sage: QQ.is_perfect()
                True
                sage: GF(2).is_perfect()
                True
                sage: FunctionField(GF(2), 'x').is_perfect()
                False

            """
            if self.characteristic() == 0:
                return True
            else: raise NotImplementedError

        def _test_characteristic_fields(self, **options):
            """
            Run generic tests on the method :meth:`.characteristic`.

            EXAMPLES::

                sage: QQ._test_characteristic_fields()

            .. NOTE::

                We cannot call this method ``_test_characteristic`` since that
                would overwrite the method in the super category, and for
                cython classes just calling
                ``super(sage.categories.fields.Fields().parent_class,
                self)._test_characteristic`` doesn't have the desired effect.

            .. SEEALSO::

                :meth:`sage.categories.rings.Rings.ParentMethods._test_characteristic`
            """
            tester = self._tester(**options)
            try:
                char = self.characteristic()
                tester.assertTrue(char.is_zero() or char.is_prime())
            except AttributeError:
                return
                # raised when self.one() does not have a additive_order() [or when char is an int and not an Integer which is already checked by _test_characteristic for rings]
            except NotImplementedError:
                return

        def fraction_field(self):
            r"""
            Returns the *fraction field* of ``self``, which is ``self``.

            EXAMPLES::

                sage: QQ.fraction_field() is QQ
                True
            """
            return self

        def _squarefree_decomposition_univariate_polynomial(self, f):
            r"""
            Return the square-free decomposition of ``f`` over this field.

            This is a helper method for
            :meth:`sage.rings.polynomial.squarefree_decomposition`.

            INPUT:

            - ``f`` -- a univariate non-zero polynomial over this field

            ALGORITHM: For rings of characteristic zero, we use the algorithm
            descriped in [Yun]_. Other fields may provide their own
            implementation by overriding this method.

            EXAMPLES::

                sage: x = polygen(QQ)
                sage: p = 37 * (x-1)^3 * (x-2)^3 * (x-1/3)^7 * (x-3/7)
                sage: p.squarefree_decomposition()
                (37*x - 111/7) * (x^2 - 3*x + 2)^3 * (x - 1/3)^7
                sage: p = 37 * (x-2/3)^2
                sage: p.squarefree_decomposition()
                (37) * (x - 2/3)^2
                sage: x = polygen(GF(3))
                sage: x.squarefree_decomposition()
                x
                sage: f = QQbar['x'](1)
                sage: f.squarefree_decomposition()
                1

            REFERENCES:

            .. [Yun] Yun, David YY. On square-free decomposition algorithms.
               In Proceedings of the third ACM symposium on Symbolic and algebraic
               computation, pp. 26-35. ACM, 1976.

            """
            from sage.structure.factorization import Factorization
            if f.degree() == 0:
                return Factorization([], unit=f[0])
            if self.characteristic() != 0:
                raise NotImplementedError("square-free decomposition not implemented for this polynomial.")

            factors = []
            cur = f
            f = [f]
            while cur.degree() > 0:
                cur = cur.gcd(cur.derivative())
                f.append(cur)

            g = []
            for i in range(len(f) - 1):
                g.append(f[i] // f[i+1])

            a = []
            for i in range(len(g) - 1):
                a.append(g[i] // g[i+1])
            a.append(g[-1])

            unit = f[-1]
            for i in range(len(a)):
                if a[i].degree() > 0:
                    factors.append((a[i], i+1))
                else:
                    unit = unit * a[i].constant_coefficient() ** (i + 1)

            return Factorization(factors, unit=unit, sort=False)

        def __pow__(self, n):
            r"""
            Returns the vector space of dimension `n` over ``self``.

            EXAMPLES::

                sage: QQ^4
                Vector space of dimension 4 over Rational Field
            """
            from sage.modules.all import FreeModule
            return FreeModule(self, n)

    class ElementMethods:
        def euclidean_degree(self):
            r"""
            Return the degree of this element as an element of a euclidean
            domain.

            In a field, this returns 0 for all but the zero element (for
            which it is undefined).

            EXAMPLES::

                sage: QQ.one().euclidean_degree()
                0
            """
            if self.is_zero():
                raise ValueError("euclidean degree not defined for the zero element")
            from sage.rings.all import ZZ
            return ZZ.zero()

        def quo_rem(self, other):
            r"""
            Return the quotient with remainder of the division of this element
            by ``other``.

            INPUT:

            - ``other`` -- an element of the field

            EXAMPLES::

                sage: f,g = QQ(1), QQ(2)
                sage: f.quo_rem(g)
                (1/2, 0)
            """
            if other.is_zero():
                raise ZeroDivisionError
            return (self/other, self.parent().zero())

        def is_unit( self ):
            r"""
            Returns True if ``self`` has a multiplicative inverse.

            EXAMPLES::

                sage: QQ(2).is_unit()
                True
                sage: QQ(0).is_unit()
                False
            """
            return not self.is_zero()

        # Fields are unique factorization domains, so, there is gcd and lcm
        # Of course, in general gcd and lcm in a field are not very interesting.
        # However, they should be implemented!
        def gcd(self,other):
            """
            Greatest common divisor.

            NOTE:

            Since we are in a field and the greatest common divisor is
            only determined up to a unit, it is correct to either return
            zero or one. Note that fraction fields of unique factorization
            domains provide a more sophisticated gcd.

            EXAMPLES::

                sage: GF(5)(1).gcd(GF(5)(1))
                1
                sage: GF(5)(1).gcd(GF(5)(0))
                1
                sage: GF(5)(0).gcd(GF(5)(0))
                0

            For fields of characteristic zero (i.e., containing the
            integers as a sub-ring), evaluation in the integer ring is
            attempted. This is for backwards compatibility::

                sage: gcd(6.0,8); gcd(6.0,8).parent()
                2
                Integer Ring

            If this fails, we resort to the default we see above::

                sage: gcd(6.0*CC.0,8*CC.0); gcd(6.0*CC.0,8*CC.0).parent()
                1.00000000000000
                Complex Field with 53 bits of precision

            AUTHOR:

            - Simon King (2011-02): Trac ticket #10771

            """
            P = self.parent()
            try:
                other = P(other)
            except (TypeError, ValueError):
                raise ArithmeticError("The second argument can not be interpreted in the parent of the first argument. Can't compute the gcd")
            from sage.rings.integer_ring import ZZ
            if ZZ.is_subring(P):
                try:
                    return ZZ(self).gcd(ZZ(other))
                except TypeError:
                    pass
            # there is no custom gcd, so, we resort to something that always exists
            # (that's new behaviour)
            if self==0 and other==0:
                return P.zero()
            return P.one()

        def lcm(self,other):
            """
            Least common multiple.

            NOTE:

            Since we are in a field and the least common multiple is
            only determined up to a unit, it is correct to either return
            zero or one. Note that fraction fields of unique factorization
            domains provide a more sophisticated lcm.

            EXAMPLES::

                sage: GF(2)(1).lcm(GF(2)(0))
                0
                sage: GF(2)(1).lcm(GF(2)(1))
                1

            If the field contains the integer ring, it is first
            attempted to compute the gcd there::

                sage: lcm(15.0,12.0); lcm(15.0,12.0).parent()
                60
                Integer Ring

            If this fails, we resort to the default we see above::

                sage: lcm(6.0*CC.0,8*CC.0); lcm(6.0*CC.0,8*CC.0).parent()
                1.00000000000000
                Complex Field with 53 bits of precision
                sage: lcm(15.2,12.0)
                1.00000000000000

            AUTHOR:

            - Simon King (2011-02): Trac ticket #10771

            """
            P = self.parent()
            try:
                other = P(other)
            except (TypeError, ValueError):
                raise ArithmeticError("The second argument can not be interpreted in the parent of the first argument. Can't compute the lcm")
            from sage.rings.integer_ring import ZZ
            if ZZ.is_subring(P):
                try:
                    return ZZ(self).lcm(ZZ(other))
                except TypeError:
                    pass
            # there is no custom lcm, so, we resort to something that always exists
            if self==0 or other==0:
                return P.zero()
            return P.one()

        @coerce_binop
        def xgcd(self, other):
            """
            Compute the extended gcd of ``self`` and ``other``.

            INPUT:

            - ``other`` -- an element with the same parent as ``self``

            OUTPUT:

            A tuple ``(r, s, t)`` of elements in the parent of ``self`` such
            that ``r = s * self + t * other``. Since the computations are done
            over a field, ``r`` is zero if ``self`` and ``other`` are zero,
            and one otherwise.

            AUTHORS:

            - Julian Rueth (2012-10-19): moved here from
              :class:`sage.structure.element.FieldElement`

            EXAMPLES::

                sage: (1/2).xgcd(2)
                (1, 2, 0)
                sage: (0/2).xgcd(2)
                (1, 0, 1/2)
                sage: (0/2).xgcd(0)
                (0, 0, 0)
            """
            R = self.parent()
            if not self.is_zero():
                return (R.one(), ~self, R.zero())
            if not other.is_zero():
                return (R.one(), R.zero(), ~other)
            # else both are 0
            return (R.zero(), R.zero(), R.zero())