Exemple #1
0
        def __init_extra__(self):
            """
            Declare the canonical coercion from ``self.base_ring()``
            to ``self``, if there has been none before.

            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: coercion_model = sage.structure.element.get_coercion_model()
                sage: coercion_model.discover_coercion(QQ, A)
                (Generic morphism:
                  From: Rational Field
                  To:   An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field, None)
                sage: A(1)          # indirect doctest
                B[word: ]

            TESTS:

            Ensure that :trac:`28328` is fixed and that non-associative
            algebras are supported::

                sage: class Foo(CombinatorialFreeModule):
                ....:     def one(self):
                ....:         return self.monomial(0)
                sage: from sage.categories.magmatic_algebras \
                ....:   import MagmaticAlgebras
                sage: C = MagmaticAlgebras(QQ).WithBasis().Unital()
                sage: F = Foo(QQ,(1,),category=C)
                sage: F(0)
                0
                sage: F(3)
                3*B[0]

            """
            # If self has an attribute _no_generic_basering_coercion
            # set to True, then this declaration is skipped.
            # This trick, introduced in #11900, is used in
            # sage.matrix.matrix_space.py and
            # sage.rings.polynomial.polynomial_ring.
            # It will hopefully be refactored into something more
            # conceptual later on.
            if getattr(self, '_no_generic_basering_coercion', False):
                return

            base_ring = self.base_ring()
            if base_ring is self:
                # There are rings that are their own base rings. No need to register that.
                return
            if self._is_coercion_cached(base_ring):
                # We will not use any generic stuff, since a (presumably) better conversion
                # has already been registered.
                return

            # Pick a homset for the morphism to live in...
            if self in Rings():
                # The algebra is associative, and thus a ring. The
                # base ring is also a ring. Everything is OK.
                H = Hom(base_ring, self, Rings())
            else:
                # If the algebra isn't associative, we would like to
                # use the category of unital magmatic algebras (which
                # are not necessarily associative) instead. But,
                # unfortunately, certain important rings like QQ
                # aren't in that category. As a result, we have to use
                # something weaker.
                cat = Magmas().Unital()
                cat = Category.join([cat, CommutativeAdditiveGroups()])
                cat = cat.Distributive()
                H = Hom(base_ring, self, cat)

            # We need to register a coercion from the base ring to self.
            #
            # There is a generic method from_base_ring(), that just does
            # multiplication with the multiplicative unit. However, the
            # unit is constructed repeatedly, which is slow.
            # So, if the unit is available *now*, then we can create a
            # faster coercion map.
            #
            # This only applies for the generic from_base_ring() method.
            # If there is a specialised from_base_ring(), then it should
            # be used unconditionally.
            generic_from_base_ring = self.category(
            ).parent_class.from_base_ring
            if type(self).from_base_ring != generic_from_base_ring:
                # Custom from_base_ring()
                use_from_base_ring = True
            if isinstance(generic_from_base_ring, lazy_attribute):
                # If the category implements from_base_ring() as lazy
                # attribute, then we always use it.
                # This is for backwards compatibility, see Trac #25181
                use_from_base_ring = True
            else:
                try:
                    one = self.one()
                    use_from_base_ring = False
                except (NotImplementedError, AttributeError, TypeError):
                    # The unit is not available, yet. But there are cases
                    # in which it will be available later. So, we use
                    # the generic from_base_ring() after all.
                    use_from_base_ring = True

            mor = None
            if use_from_base_ring:
                mor = SetMorphism(function=self.from_base_ring, parent=H)
            else:
                # We have the multiplicative unit, so implement the
                # coercion from the base ring as multiplying with that.
                #
                # But first we check that it actually works. If not,
                # then the generic implementation of from_base_ring()
                # would fail as well so we don't use it.
                try:
                    if one._lmul_(base_ring.an_element()) is not None:
                        # There are cases in which lmul returns None,
                        # which means that it's not implemented.
                        # One example: Hecke algebras.
                        mor = SetMorphism(function=one._lmul_, parent=H)
                except (NotImplementedError, AttributeError, TypeError):
                    pass
            if mor is not None:
                try:
                    self.register_coercion(mor)
                except AssertionError:
                    pass
        def _coerce_map_from_base_ring(self):
            """
            Return a suitable coercion map from the base ring of ``self``.

            TESTS::

                sage: A = cartesian_product((QQ['z'],)); A
                The Cartesian product of (Univariate Polynomial Ring in z over Rational Field,)
                sage: A.base_ring()
                Rational Field
                sage: A._coerce_map_from_base_ring()
                Generic morphism:
                From: Rational Field
                To:   The Cartesian product of (Univariate Polynomial Ring in z over Rational Field,)

            Check that :trac:`29312` is fixed::

                sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
                sage: F._coerce_map_from_base_ring()
                Generic morphism:
                  From: Rational Field
                  To:   Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
            """
            base_ring = self.base_ring()

            # Pick a homset for the morphism to live in...
            if self in Rings():
                # The algebra is associative, and thus a ring. The
                # base ring is also a ring. Everything is OK.
                H = Hom(base_ring, self, Rings())
            else:
                # If the algebra isn't associative, we would like to
                # use the category of unital magmatic algebras (which
                # are not necessarily associative) instead. But,
                # unfortunately, certain important rings like QQ
                # aren't in that category. As a result, we have to use
                # something weaker.
                cat = Magmas().Unital()
                cat = Category.join([cat, CommutativeAdditiveGroups()])
                cat = cat.Distributive()
                H = Hom(base_ring, self, cat)

            # We need to construct a coercion from the base ring to self.
            #
            # There is a generic method from_base_ring(), that just does
            # multiplication with the multiplicative unit. However, the
            # unit is constructed repeatedly, which is slow.
            # So, if the unit is available *now*, then we can create a
            # faster coercion map.
            #
            # This only applies for the generic from_base_ring() method.
            # If there is a specialised from_base_ring(), then it should
            # be used unconditionally.
            generic_from_base_ring = self.category(
            ).parent_class.from_base_ring
            from_base_ring = self.from_base_ring  # bound method
            if from_base_ring.__func__ != generic_from_base_ring:
                # Custom from_base_ring()
                use_from_base_ring = True
            elif isinstance(generic_from_base_ring, lazy_attribute):
                # If the category implements from_base_ring() as lazy
                # attribute, then we always use it.
                # This is for backwards compatibility, see Trac #25181
                use_from_base_ring = True
            else:
                try:
                    one = self.one()
                    use_from_base_ring = False
                except (NotImplementedError, AttributeError, TypeError):
                    # The unit is not available, yet. But there are cases
                    # in which it will be available later. So, we use
                    # the generic from_base_ring() after all.
                    use_from_base_ring = True

            mor = None
            if use_from_base_ring:
                mor = SetMorphism(function=from_base_ring, parent=H)
            else:
                # We have the multiplicative unit, so implement the
                # coercion from the base ring as multiplying with that.
                #
                # But first we check that it actually works. If not,
                # then the generic implementation of from_base_ring()
                # would fail as well so we don't use it.
                try:
                    if one._lmul_(base_ring.an_element()) is not None:
                        # There are cases in which lmul returns None,
                        # which means that it's not implemented.
                        # One example: Hecke algebras.
                        mor = SetMorphism(function=one._lmul_, parent=H)
                except (NotImplementedError, AttributeError, TypeError):
                    pass
            return mor