def __init__(self, hall_littlewood):
        r"""
        A class with methods for working with Hall-Littlewood symmetric functions which
        are common to all bases.

        INPUT:

        - ``self`` -- a Hall-Littlewood symmetric function basis
        - ``hall_littlewood`` -- a class of Hall-Littlewood bases

        TESTS::

            sage: SymmetricFunctions(QQ['t'].fraction_field()).hall_littlewood().P()
            Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the Hall-Littlewood P basis
            sage: SymmetricFunctions(QQ).hall_littlewood(t=2).P()
            Symmetric Functions over Rational Field in the Hall-Littlewood P with t=2 basis
        """
        s = self.__class__.__name__[15:].capitalize()
        sfa.SymmetricFunctionAlgebra_generic.__init__(
            self,
            hall_littlewood._sym,
            basis_name="Hall-Littlewood " + s + hall_littlewood._name_suffix,
            prefix="HL" + s)
        self.t = hall_littlewood.t
        self._sym = hall_littlewood._sym
        self._hall_littlewood = hall_littlewood
        self._s = self._sym.schur()

        # This coercion is broken: HLP = HallLittlewoodP(QQ); HLP(HLP._s[1])

        # Bases defined by orthotriangularity should inherit from some
        # common category BasesByOrthotriangularity (shared with Jack, HL, orthotriang, Mcdo)
        if hasattr(self, "_s_cache"):
            # temporary until Hom(GradedHopfAlgebrasWithBasis work better)
            category = sage.categories.all.ModulesWithBasis(
                self._sym.base_ring())
            self.register_coercion(
                SetMorphism(Hom(self._s, self, category), self._s_to_self))
            self._s.register_coercion(
                SetMorphism(Hom(self, self._s, category), self._self_to_s))
    def _composition_(self, right, homset):
        """
        Helper to construct the composition of two morphisms.

        Override this if you want to have a different behaviour of composition

        INPUT:

        - ``right`` -- a map or callable
        - ``homset`` -- a homset containing the composed map

        OUTPUT:

        An element of ``homset``. The output is obtained by converting the
        arguments to :class:`~sage.categories.morphism.SetMorphism` if
        necessary, and then forming a :class:`~sage.categories.map.FormalCompositeMap`

        EXAMPLES::

            sage: X = AffineSpace(QQ,2)
            sage: f = X.structure_morphism()
            sage: Y = Spec(QQ)
            sage: g = Y.structure_morphism()
            sage: g * f    # indirect doctest
             Composite map:
              From: Affine Space of dimension 2 over Rational Field
              To:   Spectrum of Integer Ring
              Defn:   Generic morphism:
                      From: Affine Space of dimension 2 over Rational Field
                      To:   Spectrum of Rational Field
                    then
                      Generic morphism:
                      From: Spectrum of Rational Field
                      To:   Spectrum of Integer Ring
        """
        if not isinstance(right, Map):
            right = SetMorphism(right.parent(), right)
        return FormalCompositeMap(homset, right,
                                  SetMorphism(self.parent(), self))
Exemple #3
0
    def __init__(self, llt, prefix):
        r"""
        A class of methods which are common to both the hspin and hcospin
        of the LLT symmetric functions.

        INPUT:

        - ``self`` -- an instance of the LLT hspin or hcospin basis
        - ``llt`` -- a family of LLT symmetric functions

        EXAMPLES::

            sage: SymmetricFunctions(FractionField(QQ['t'])).llt(3).hspin()
            Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the level 3 LLT spin basis
            sage: SymmetricFunctions(QQ).llt(3,t=2).hspin()
            Symmetric Functions over Rational Field in the level 3 LLT spin with t=2 basis
            sage: QQz = FractionField(QQ['z']); z = QQz.gen()
            sage: SymmetricFunctions(QQz).llt(3,t=z).hspin()
            Symmetric Functions over Fraction Field of Univariate Polynomial Ring in z over Rational Field in the level 3 LLT spin with t=z basis
        """
        s = self.__class__.__name__[4:]
        sfa.SymmetricFunctionAlgebra_generic.__init__(
            self, llt._sym,
            basis_name = "level %s LLT "%llt.level() + s + llt._name_suffix,
            prefix = prefix)

        self.t = llt.t
        self._sym = llt._sym
        self._llt = llt
        self._k = llt._k

        sfa.SymmetricFunctionAlgebra_generic.__init__(self, self._sym)

        # temporary until Hom(GradedHopfAlgebrasWithBasis work better)
        category = sage.categories.all.ModulesWithBasis(self._sym.base_ring())
        self._m = llt._sym.m()
        self   .register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self))
        self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m))
Exemple #4
0
    def section(self):
        """
        Return the section map of ``self``.

        EXAMPLES::

            sage: R = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: L.<x,y,z> = LieAlgebra(associative=R.gens())
            sage: f = R.coerce_map_from(L)
            sage: f.section()
            Generic morphism:
              From: Free Algebra on 3 generators (x, y, z) over Rational Field
              To:   Lie algebra generated by (x, y, z) in Free Algebra on 3 generators (x, y, z) over Rational Field
        """
        return SetMorphism(Hom(self.codomain(), self.domain()), self.preimage)
Exemple #5
0
    def zero(self):
        """
        Return the zero morphism.

        EXAMPLES::

            sage: L = LieAlgebra(QQ, 'x,y,z')
            sage: Lyn = L.Lyndon()
            sage: H = L.Hall()
            sage: HS = Hom(Lyn, H)
            sage: HS.zero()
            Generic morphism:
              From: Free Lie algebra generated by (x, y, z) over Rational Field in the Lyndon basis
              To:   Free Lie algebra generated by (x, y, z) over Rational Field in the Hall basis
        """
        return SetMorphism(self, lambda x: self.codomain().zero())
Exemple #6
0
    def __init__(self, I, L, names, index_set, category=None):
        r"""
        Initialize ``self``.

        TESTS::

            sage: L.<x,y,z> = LieAlgebra(SR, {('x','y'): {'x':1}})
            sage: K = L.quotient(y)
            sage: K.dimension()
            1
            sage: TestSuite(K).run()
        """
        B = L.basis()
        sm = L.module().submodule_with_basis(
            [I.reduce(B[i]).to_vector() for i in index_set])
        SB = sm.basis()

        # compute and normalize structural coefficients for the quotient
        s_coeff = {}
        for i, ind_i in enumerate(index_set):
            for j in range(i + 1, len(index_set)):
                ind_j = index_set[j]

                brkt = I.reduce(L.bracket(SB[i], SB[j]))
                brktvec = sm.coordinate_vector(brkt.to_vector())
                s_coeff[(ind_i, ind_j)] = dict(zip(index_set, brktvec))
        s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(
            s_coeff, index_set)

        self._ambient = L
        self._I = I
        self._sm = sm

        LieAlgebraWithStructureCoefficients.__init__(self,
                                                     L.base_ring(),
                                                     s_coeff,
                                                     names,
                                                     index_set,
                                                     category=category)

        # register the quotient morphism as a conversion
        H = Hom(L, self)
        f = SetMorphism(H, self.retract)
        self.register_conversion(f)
Exemple #7
0
    def __init__(self, R, repr_var1 = 'x', repr_var2 = 'y', inversed_ring = None):
        self._coeffs_ring = MultivariatePolynomialAlgebra_generic(R, repr_var2, always_show_main_var = True)
        MultivariatePolynomialAlgebra_generic.__init__(
            self,
            self._coeffs_ring,
            repr_var1,
            always_show_main_var = True,
            extra_bases_category = Finite_rank_double_bases()
        )
        self._repr_var1 = repr_var1
        self._repr_var2 = repr_var2
        self._coeffs_base_ring = R
        if(inversed_ring is None):
            self._inversed_ring = DoubleMultivariatePolynomialAlgebra_generic(R, repr_var2, repr_var1, self)
        else:
            self._inversed_ring = inversed_ring

        m = SetMorphism( Hom(self, self.inversed_ring()), lambda x : x.swap_coeffs_elements())
        m.register_as_coercion()
Exemple #8
0
    def _coerce_map_from_(self, S):
        """
        Define coercions.

        EXAMPLES:

        A place is converted to a prime divisor::

            sage: K.<x> = FunctionField(GF(5)); R.<t> = PolynomialRing(K)
            sage: F.<y> = K.extension(t^2-x^3-1)
            sage: O = F.maximal_order()
            sage: I = O.ideal(x+1,y)
            sage: P = I.place()
            sage: y.divisor() + P
            -3*Place (1/x, 1/x^2*y)
             + 2*Place (x + 1, y)
             + Place (x^2 + 4*x + 1, y)
        """
        if isinstance(S, PlaceSet):
            func = lambda place: prime_divisor(self._field, place)
            return SetMorphism(Hom(S, self), func)
Exemple #9
0
        def module_morphism(self,
                            *,
                            function,
                            category=None,
                            codomain,
                            **keywords):
            r"""
            Construct a module morphism from ``self`` to ``codomain``.

            Let ``self`` be a module `X` over a ring `R`.
            This constructs a morphism `f: X \to Y`.

            INPUT:

            - ``self`` -- a parent `X` in ``Modules(R)``.

            - ``function`` -- a function `f` from `X` to `Y`

            - ``codomain`` -- the codomain `Y` of the morphism (default:
              ``f.codomain()`` if it's defined; otherwise it must be specified)

            - ``category`` -- a category or ``None`` (default: ``None``)

            EXAMPLES::

                sage: V = FiniteRankFreeModule(QQ, 2)
                sage: e = V.basis('e'); e
                Basis (e_0,e_1) on the 2-dimensional vector space over the Rational Field
                sage: neg = V.module_morphism(function=operator.neg, codomain=V); neg
                Generic endomorphism of 2-dimensional vector space over the Rational Field
                sage: neg(e[0])
                Element -e_0 of the 2-dimensional vector space over the Rational Field

            """
            # Make sure that we only create a module morphism, even if
            # domain and codomain have more structure
            if category is None:
                category = Modules(self.base_ring())
            return SetMorphism(Hom(self, codomain, category), function)
Exemple #10
0
    def __init__(self, ambient, gens, ideal, order=None, category=None):
        r"""
        Initialize ``self``.

        TESTS::

            sage: L.<X,Y,Z> = LieAlgebra(QQ, {('X','Y'): {'Z': 1}})
            sage: S = L.subalgebra(X)
            sage: TestSuite(S).run()
            sage: I = L.ideal(X)
            sage: TestSuite(I).run()
        """
        self._ambient = ambient
        self._gens = gens
        self._is_ideal = ideal

        # initialize helper variables for ordering
        if order is None:
            if hasattr(ambient, "_basis_key"):
                order = ambient._basis_key
            else:
                order = lambda x: x
        self._order = order
        self._reversed_indices = sorted(ambient.indices(),
                                        key=order,
                                        reverse=True)
        # helper to reorder a vector that has been jumbled by the above
        self._reorganized_indices = [
            self._reversed_indices.index(i) for i in ambient.indices()
        ]

        sup = super(LieSubalgebra_finite_dimensional_with_basis, self)
        sup.__init__(ambient.base_ring(), category=category)

        # register a coercion to the ambient Lie algebra
        H = Hom(self, ambient)
        f = SetMorphism(H, self.lift)
        ambient.register_coercion(f)
Exemple #11
0
    def _apply_functor_to_morphism(self, f) :
        r"""
        Lift a homomorphism of rings to the corresponding homomorphism of the group algebras of ``self.group()``.

        INPUT:

        - ``f`` - a morphism of rings.

        OUTPUT:

        A morphism of group algebras.

        EXAMPLES::

            sage: G = SymmetricGroup(3)
            sage: A = GroupAlgebra(G, ZZ)
            sage: h = sage.categories.morphism.SetMorphism(Hom(ZZ, GF(5), Rings()), lambda x: GF(5)(x))
            sage: hh = A.construction()[0](h)
            sage: hh(A.0 + 5 * A.1)
            (1,2,3)
        """
        codomain = self(f.codomain())
        return SetMorphism(Hom(self(f.domain()), codomain, Rings()), lambda x: sum(codomain(g) * f(c) for (g, c) in dict(x).iteritems()))
Exemple #12
0
    def _apply_functor_to_morphism(self, f):
        r"""
        Given a morphism of commutative additive groups, return the corresponding morphism
        of multiplicative groups.

        INPUT:

        - A homomorphism `f` of commutative additive groups.

        OUTPUT:

        - The above homomorphism, but between the corresponding multiplicative groups.

        In the following example, ``self`` is the functor `GroupExp()` and `f` is an endomorphism of the
        additive group of integers.

        EXAMPLES::

            sage: def double(x):
            ....:     return x + x
            sage: from sage.categories.morphism import SetMorphism
            sage: from sage.categories.homset import Hom
            sage: f = SetMorphism(Hom(ZZ,ZZ,CommutativeAdditiveGroups()),double)
            sage: E = GroupExp()
            sage: EZ = E._apply_functor(ZZ)
            sage: F = E._apply_functor_to_morphism(f)
            sage: F.domain() == EZ
            True
            sage: F.codomain() == EZ
            True
            sage: F(EZ(3)) == EZ(3)*EZ(3)
            True
        """
        new_domain = self._apply_functor(f.domain())
        new_codomain = self._apply_functor(f.codomain())
        new_f = lambda a: new_codomain(f(a.value))
        return SetMorphism(Hom(new_domain, new_codomain, Groups()), new_f)
Exemple #13
0
    def __init__(self, root_system, base_ring):
        """
        EXAMPLES::

            sage: P = RootSystem(['A',4]).root_space()
            sage: s = P.simple_reflections()

        """
        from sage.categories.morphism import SetMorphism
        from sage.categories.homset import Hom
        from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
        self.root_system = root_system
        CombinatorialFreeModule.__init__(self, base_ring,
                                         root_system.index_set(),
                                         prefix = "alphacheck" if root_system.dual_side else "alpha",
                                         latex_prefix = "\\alpha^\\vee" if root_system.dual_side else "\\alpha",
                                         category = RootLatticeRealizations(base_ring))
        if base_ring is not ZZ:
            # Register the partial conversion back from ``self`` to the root lattice
            # See :meth:`_to_root_lattice` for tests
            root_lattice = self.root_system.root_lattice()
            SetMorphism(Hom(self, root_lattice, SetsWithPartialMaps()),
                        self._to_root_lattice
                        ).register_as_conversion()
Exemple #14
0
    def _normalize_morphism(self, category):
        """
        Returns the normalize morphism

        EXAMPLES::

            sage: P = JackPolynomialsP(QQ); P.rename("JackP")
            sage: normal = P._normalize_morphism(AlgebrasWithBasis(P.base_ring()))
            sage: normal.parent()
            Set of Homomorphisms from JackP to JackP
            sage: normal.category_for()
            Category of algebras with basis over Fraction Field of Univariate Polynomial Ring in t over Rational Field

            sage: t = P.t
            sage: a = 2/(1/2*t+1/2)
            sage: b = 1/(1/3+1/6*t)
            sage: c = 24/(4*t^2 + 12*t + 8)
            sage: normal( a*P[1] + b*P[2] + c*P[2,1] )
            (4/(t+1))*JackP[1] + (6/(t+2))*JackP[2] + (6/(t^2+3*t+2))*JackP[2, 1]

        TODO: this method should not be needed once short idioms to
        construct morphisms will be available
        """
        return SetMorphism(End(self, category), self._normalize)
Exemple #15
0
    def _apply_functor_to_morphism(self, f):
        r"""
        Lift a homomorphism of rings to the corresponding homomorphism
        of the group algebras of ``self.group()``.

        INPUT:

        - ``f`` -- a morphism of rings

        OUTPUT:

        A morphism of group algebras.

        EXAMPLES::

            sage: G = SymmetricGroup(3)
            sage: A = GroupAlgebra(G, ZZ)
            sage: h = GF(5).coerce_map_from(ZZ)
            sage: hh = A.construction()[0](h); hh
            Generic morphism:
              From: Symmetric group algebra of order 3 over Integer Ring
              To:   Symmetric group algebra of order 3 over Finite Field of size 5

            sage: a = 2 * A.an_element(); a
            2*() + 2*(2,3) + 6*(1,2,3) + 4*(1,3,2)
            sage: hh(a)
            2*() + 2*(2,3) + (1,2,3) + 4*(1,3,2)
        """
        from sage.categories.rings import Rings
        domain = self(f.domain())
        codomain = self(f.codomain())
        # we would want to use something like:
        # domain.module_morphism(on_coefficients=h, codomain=codomain, category=Rings())
        return SetMorphism(
            domain.Hom(codomain, category=Rings()),
            lambda x: codomain.sum_of_terms((g, f(c)) for (g, c) in x))
        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
Exemple #17
0
    def __init__(self, dual_basis, scalar, scalar_name="", prefix=None):
        """
        Generic dual base of a basis of symmetric functions.

        EXAMPLES::

            sage: h = SFAElementary(QQ)
            sage: f = h.dual_basis(prefix = "m")
            sage: TestSuite(f).run()  # long time (11s on sage.math, 2011)

        This class defines canonical coercions between self and
        self^*, as follow:

        Lookup for the canonical isomorphism from self to `P`
        (=powersum), and build the adjoint isomorphism from `P^*` to
        self^*. Since `P` is self-adjoint for this scalar product,
        derive an isomorphism from `P` to `self^*`, and by composition
        with the above get an isomorphism from self to `self^*` (and
        similarly for the isomorphism `self^*` to `self`).

        This should be striped down to just (auto?) defining canonical
        isomorphism by adjunction (as in MuPAD-Combinat), and let
        the coercion handle the rest.

        By transitivity, this defines indirect coercions to and from all other bases::

            sage: s = SFASchur(QQ['t'].fraction_field())
            sage: t = QQ['t'].fraction_field().gen()
            sage: zee_hl = lambda x: x.centralizer_size(t=t)
            sage: S = s.dual_basis(zee_hl)
            sage: S(s([2,1]))
            (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[1, 1, 1] + ((-t^2-1)/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[2, 1] + (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[3]
        """
        self._dual_basis = dual_basis
        self._scalar = scalar
        self._scalar_name = scalar_name

        #Set up the cache
        self._to_self_cache = {}
        self._from_self_cache = {}
        self._transition_matrices = {}
        self._inverse_transition_matrices = {}

        #
        scalar_target = scalar(sage.combinat.partition.Partition_class(
            [1])).parent()
        scalar_target = (scalar_target(1) * dual_basis.base_ring()(1)).parent()

        self._p = sfa.SFAPower(scalar_target)

        if prefix is None:
            prefix = 'd_' + dual_basis.prefix()

        classical.SymmetricFunctionAlgebra_classical.__init__(
            self, scalar_target, "dual_" + dual_basis.basis_name(), prefix)

        # temporary until Hom(GradedHopfAlgebrasWithBasis work better)
        category = sage.categories.all.ModulesWithBasis(self.base_ring())
        self.register_coercion(
            SetMorphism(Hom(self._dual_basis, self, category),
                        self._dual_to_self))
        self._dual_basis.register_coercion(
            SetMorphism(Hom(self, self._dual_basis, category),
                        self._self_to_dual))
Exemple #18
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
Exemple #19
0
    def __init__(self,
                 dual_basis,
                 scalar,
                 scalar_name="",
                 basis_name=None,
                 prefix=None):
        """
        Generic dual base of a basis of symmetric functions.

        INPUT:

        - ``self`` -- a dual basis of the symmetric functions
        - ``dual_basis`` -- a basis of the symmetric functions dual to ``self``
        - ``scalar`` -- a function `zee` on partitions which determines the scalar product
          on the power sum basis with normalization `<p_\mu, p_\mu> = zee(\mu)`.
        - ``scalar_name`` -- a string giving a description of the scalar product
          specified by the parameter ``scalar`` (default : the empty string)
        - ``prefix`` -- a string to use as the symbol for the basis.  The default
          string will be "d" + the prefix for ``dual_basis``

        EXAMPLES::

            sage: e = SymmetricFunctions(QQ).e()
            sage: f = e.dual_basis(prefix = "m", basis_name="Forgotten symmetric functions"); f
            Symmetric Functions over Rational Field in the Forgotten symmetric functions basis
            sage: TestSuite(f).run(elements = [f[1,1]+2*f[2], f[1]+3*f[1,1]])
            sage: TestSuite(f).run() # long time (11s on sage.math, 2011)

        This class defines canonical coercions between ``self`` and
        ``self^*``, as follow:

        Lookup for the canonical isomorphism from ``self`` to `P`
        (=powersum), and build the adjoint isomorphism from `P^*` to
        ``self^*``. Since `P` is self-adjoint for this scalar product,
        derive an isomorphism from `P` to ``self^*``, and by composition
        with the above get an isomorphism from ``self`` to ``self^*`` (and
        similarly for the isomorphism ``self^*`` to ``self``).

        This should be striped down to just (auto?) defining canonical
        isomorphism by adjunction (as in MuPAD-Combinat), and let
        the coercion handle the rest.

        Inversions may not be possible if the base ring is not a field::

            sage: m = SymmetricFunctions(ZZ).m()
            sage: h = m.dual_basis(sage.combinat.sf.sfa.zee)
            sage: h[2,1]
            Traceback (most recent call last):
            ...
            TypeError: no conversion of this rational to integer

        By transitivity, this defines indirect coercions to and from all other bases::

            sage: s = SymmetricFunctions(QQ['t'].fraction_field()).s()
            sage: t = QQ['t'].fraction_field().gen()
            sage: zee_hl = lambda x: x.centralizer_size(t=t)
            sage: S = s.dual_basis(zee_hl)
            sage: S(s([2,1]))
            (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[1, 1, 1] + ((-t^2-1)/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[2, 1] + (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[3]

        TESTS:

        Regression test for :trac:`12489`. This ticked improving
        equality test revealed that the conversion back from the dual
        basis did not strip cancelled terms from the dictionary::

            sage: y = e[1, 1, 1, 1] - 2*e[2, 1, 1] + e[2, 2]
            sage: sorted(f.element_class(f, dual = y))
            [([1, 1, 1, 1], 6), ([2, 1, 1], 2), ([2, 2], 1)]

        """
        self._dual_basis = dual_basis
        self._scalar = scalar
        self._scalar_name = scalar_name

        #Set up the cache
        self._to_self_cache = {}
        self._from_self_cache = {}
        self._transition_matrices = {}
        self._inverse_transition_matrices = {}

        #
        scalar_target = scalar(sage.combinat.partition.Partition([1])).parent()
        scalar_target = (scalar_target(1) * dual_basis.base_ring()(1)).parent()

        self._sym = sage.combinat.sf.sf.SymmetricFunctions(scalar_target)
        self._p = self._sym.power()

        if prefix is None:
            prefix = 'd_' + dual_basis.prefix()

        classical.SymmetricFunctionAlgebra_classical.__init__(
            self, self._sym, basis_name=basis_name, prefix=prefix)

        # temporary until Hom(GradedHopfAlgebrasWithBasis work better)
        category = sage.categories.all.ModulesWithBasis(self.base_ring())
        self.register_coercion(
            SetMorphism(Hom(self._dual_basis, self, category),
                        self._dual_to_self))
        self._dual_basis.register_coercion(
            SetMorphism(Hom(self, self._dual_basis, category),
                        self._self_to_dual))
Exemple #20
0
    def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=None):
        r"""
        Generic dual basis of a basis of symmetric functions.

        INPUT:

        - ``dual_basis`` -- a basis of the ring of symmetric functions

        - ``scalar`` -- A function `z` on partitions which determines the
          scalar product on the power sum basis by
          `\langle p_{\mu}, p_{\mu} \rangle = z(\mu)`. (Independently on the
          function chosen, the power sum basis will always be orthogonal; the
          function ``scalar`` only determines the norms of the basis elements.)
          This defaults to the function ``zee`` defined in
          ``sage.combinat.sf.sfa``, that is, the function is defined by:

          .. MATH::

              \lambda \mapsto \prod_{i = 1}^\infty m_i(\lambda)!
              i^{m_i(\lambda)}`,

          where `m_i(\lambda)` means the number of times `i` appears in
          `\lambda`. This default function gives the standard Hall scalar
          product on the ring of symmetric functions.

        - ``scalar_name`` -- (default: the empty string) a string giving a
          description of the scalar product specified by the parameter
          ``scalar``

        - ``basis_name`` -- (optional) a string to serve as name for the basis
          to be generated (such as "forgotten" in "the forgotten basis"); don't
          set it to any of the already existing basis names (such as
          ``homogeneous``, ``monomial``, ``forgotten``, etc.).

        - ``prefix`` -- (default: ``'d'`` and the prefix for ``dual_basis``)
          a string to use as the symbol for the basis

        OUTPUT:

        The basis of the ring of symmetric functions dual to the basis
        ``dual_basis`` with respect to the scalar product determined
        by ``scalar``.

        EXAMPLES::

            sage: e = SymmetricFunctions(QQ).e()
            sage: f = e.dual_basis(prefix = "m", basis_name="Forgotten symmetric functions"); f
            Symmetric Functions over Rational Field in the Forgotten symmetric functions basis
            sage: TestSuite(f).run(elements = [f[1,1]+2*f[2], f[1]+3*f[1,1]])
            sage: TestSuite(f).run() # long time (11s on sage.math, 2011)

        This class defines canonical coercions between ``self`` and
        ``self^*``, as follow:

        Lookup for the canonical isomorphism from ``self`` to `P`
        (=powersum), and build the adjoint isomorphism from `P^*` to
        ``self^*``. Since `P` is self-adjoint for this scalar product,
        derive an isomorphism from `P` to ``self^*``, and by composition
        with the above get an isomorphism from ``self`` to ``self^*`` (and
        similarly for the isomorphism ``self^*`` to ``self``).

        This should be striped down to just (auto?) defining canonical
        isomorphism by adjunction (as in MuPAD-Combinat), and let
        the coercion handle the rest.

        Inversions may not be possible if the base ring is not a field::

            sage: m = SymmetricFunctions(ZZ).m()
            sage: h = m.dual_basis(lambda x: 1)
            sage: h[2,1]
            Traceback (most recent call last):
            ...
            TypeError: no conversion of this rational to integer

        By transitivity, this defines indirect coercions to and from all other bases::

            sage: s = SymmetricFunctions(QQ['t'].fraction_field()).s()
            sage: t = QQ['t'].fraction_field().gen()
            sage: zee_hl = lambda x: x.centralizer_size(t=t)
            sage: S = s.dual_basis(zee_hl)
            sage: S(s([2,1]))
            (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[1, 1, 1] + ((-t^2-1)/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[2, 1] + (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[3]

        TESTS:

        Regression test for :trac:`12489`. This ticket improving
        equality test revealed that the conversion back from the dual
        basis did not strip cancelled terms from the dictionary::

            sage: y = e[1, 1, 1, 1] - 2*e[2, 1, 1] + e[2, 2]
            sage: sorted(f.element_class(f, dual = y))
            [([1, 1, 1, 1], 6), ([2, 1, 1], 2), ([2, 2], 1)]

        """
        self._dual_basis = dual_basis
        self._scalar = scalar
        self._scalar_name = scalar_name

        # Set up the cache

        # cache for the coordinates of the elements
        # of ``dual_basis`` with respect to ``self``
        self._to_self_cache = {}
        # cache for the coordinates of the elements
        # of ``self`` with respect to ``dual_basis``
        self._from_self_cache = {}
        # cache for transition matrices which contain the coordinates of
        # the elements of ``dual_basis`` with respect to ``self``
        self._transition_matrices = {}
        # cache for transition matrices which contain the coordinates of
        # the elements of ``self`` with respect to ``dual_basis``
        self._inverse_transition_matrices = {}

        scalar_target = scalar(sage.combinat.partition.Partition([1])).parent()
        scalar_target = (scalar_target.one()*dual_basis.base_ring().one()).parent()

        self._sym = sage.combinat.sf.sf.SymmetricFunctions(scalar_target)
        self._p = self._sym.power()

        if prefix is None:
            prefix = 'd_'+dual_basis.prefix()

        classical.SymmetricFunctionAlgebra_classical.__init__(self, self._sym,
                                                              basis_name = basis_name,
                                                              prefix = prefix)

        # temporary until Hom(GradedHopfAlgebrasWithBasis work better)
        category = sage.categories.all.ModulesWithBasis(self.base_ring())
        self            .register_coercion(SetMorphism(Hom(self._dual_basis, self, category), self._dual_to_self))
        self._dual_basis.register_coercion(SetMorphism(Hom(self, self._dual_basis, category), self._self_to_dual))
Exemple #21
0
    def __init__(self,
                 Sym,
                 base,
                 scalar,
                 prefix,
                 basis_name,
                 leading_coeff=None):
        r"""
        Initialization of the symmetric function algebra defined via orthotriangular rules.

        INPUT:

        - ``self`` -- a basis determined by an orthotriangular definition
        - ``Sym`` -- ring of symmetric functions
        - ``base`` -- an instance of a basis of the ring of symmetric functions
          (e.g. the Schur functions)
        - ``scalar`` -- a function ``zee`` on partitions. The function
          ``zee`` determines the scalar product on the power sum basis
          with normalization `\langle p_{\mu}, p_{\mu} \rangle =
          \mathrm{zee}(\mu)`.
        - ``prefix`` -- the prefix used to display the basis
        - ``basis_name`` -- the name used for the basis

        .. NOTE::

            The base ring is required to be a `\QQ`-algebra for this
            method to be useable, since the scalar product is defined by
            its values on the power sum basis.

        EXAMPLES::

            sage: from sage.combinat.sf.sfa import zee
            sage: from sage.combinat.sf.orthotriang import SymmetricFunctionAlgebra_orthotriang
            sage: Sym = SymmetricFunctions(QQ)
            sage: m = Sym.m()
            sage: s = SymmetricFunctionAlgebra_orthotriang(Sym, m, zee, 's', 'Schur'); s
            Symmetric Functions over Rational Field in the Schur basis

        TESTS::

            sage: TestSuite(s).run(elements = [s[1,1]+2*s[2], s[1]+3*s[1,1]])
            sage: TestSuite(s).run(skip = ["_test_associativity", "_test_prod"])  # long time (7s on sage.math, 2011)

        Note: ``s.an_element()`` is of degree 4; so we skip
        ``_test_associativity`` and ``_test_prod`` which involve
        (currently?) expensive calculations up to degree 12.
        """
        self._sym = Sym
        self._sf_base = base
        self._scalar = scalar
        self._leading_coeff = leading_coeff
        sfa.SymmetricFunctionAlgebra_generic.__init__(self,
                                                      Sym,
                                                      prefix=prefix,
                                                      basis_name=basis_name)

        self._self_to_base_cache = {}
        self._base_to_self_cache = {}
        self.register_coercion(SetMorphism(Hom(base, self),
                                           self._base_to_self))
        base.register_coercion(SetMorphism(Hom(self, base),
                                           self._self_to_base))
Exemple #22
0
def absolute_extension(self):
    """
    Return a ring isomorphic to this ring which is not a
    :class:`PolynomialQuotientRing` but of a type which offers more
    functionality.

    INUPT:

    - ``name`` -- a list of strings or ``None`` (default: ``None``), the
      name of the generator of the absolute extension. If ``None``, this
      will be the same as the name of the generator of this ring.

    EXAMPLES::

        sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
        sage: k.<a> = GF(4)
        sage: R.<b> = k[]
        sage: l.<b> = k.extension(b^2+b+a); l
        Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a
        sage: from_ll,to_ll, ll = l.absolute_extension(); ll
        Finite Field in v4 of size 2^4
        sage: all([to_ll(from_ll(ll.gen()**i)) == ll.gen()**i for i in range(ll.degree())])
        True

        sage: R.<c> = l[]
        sage: m.<c> = l.extension(c^2+b*c+b); m
        Univariate Quotient Polynomial Ring in c over Univariate Quotient Polynomial Ring in b over Finite Field in a of size 2^2 with modulus b^2 + b + a with modulus c^2 + b*c + b
        sage: from_mm, to_mm, mm = m.absolute_extension(); mm
        Finite Field in v8 of size 2^8
        sage: all([to_mm(from_mm(mm.gen()**i)) == mm.gen()**i for i in range(mm.degree())])
        True

    """
    from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
    if not self.is_field():
        raise NotImplementedError("absolute_extension() only implemented for fields")

    if self.is_finite():
        if self.base_ring().is_prime_field():
            if self.modulus().degree() == 1:
                ret = self.base_ring()
                from sage.categories.homset import Hom
                from sage.categories.morphism import SetMorphism
                to_ret = SetMorphism(Hom(self, ret), lambda x: x.lift()[0])
                from_ret = self.coerce_map_from(ret)
                return from_ret, to_ret, ret
            else:
                raise NotImplementedError

        if isinstance(self.base_ring(), PolynomialQuotientRing_generic):
            abs_base_to_base, base_to_abs_base, abs_base = self.base_ring().absolute_extension()
            modulus_over_abs_base = self.modulus().map_coefficients(lambda c:base_to_abs_base(c), abs_base)
            new_self = modulus_over_abs_base.parent().quo(modulus_over_abs_base)
            ret_to_new_self, new_self_to_ret, ret = new_self.absolute_extension()
            from_ret = ret.hom([ret_to_new_self(ret.gen()).lift().map_coefficients(abs_base_to_base, self.base_ring())(self.gen())], check=False)
            to_ret = lambda x: x.lift().map_coefficients(lambda c: new_self_to_ret(base_to_abs_base(c)), ret)(new_self_to_ret(new_self.gen()))
            from sage.categories.homset import Hom
            from sage.categories.morphism import SetMorphism
            to_ret = SetMorphism(Hom(self, ret), to_ret)
            return from_ret, to_ret, ret
        else:
            N = self.cardinality()
            from sage.rings.all import GF
            ret = GF(N,prefix='v')
            base_to_ret = self.base_ring().hom([self.base_ring().modulus().change_ring(ret).roots()[0][0]])
            im_gen = self.modulus().map_coefficients(lambda c:base_to_ret(c), ret).roots()[0][0]
            to_ret = lambda x: x.lift().map_coefficients(base_to_ret, ret)(im_gen)
            from sage.categories.homset import Hom
            from sage.categories.morphism import SetMorphism
            to_ret = SetMorphism(Hom(self, ret), to_ret)

            basis = [self.gen()**i*self.base_ring().gen()**j for i in range(self.degree()) for j in range(self.base_ring().degree())]
            assert len(basis) == ret.degree()
            basis_in_ret = [to_ret(b)._vector_() for b in basis]
            from sage.matrix.constructor import matrix
            A = matrix(basis_in_ret)
            assert A.is_square()
            x = A.solve_left(A.column_space().basis()[1])
            from_ret = ret.hom([sum(c*b for c,b in zip(x.list(),basis))], check=False)
            return from_ret, to_ret, ret
    else:
        raise NotImplementedError
Exemple #23
0
    def _coerce_map_from_(self, S):
        r"""
        Return a coercion from `S` or ``None``.

        INPUT:

        - ``S`` -- a parent

        Let us write ``self`` as `R[G]`. This method handles
        the case where `S` is another group/monoid/...-algebra
        `R'[H]`, with R coercing into `R'` and `H` coercing
        into `G`. In that case it returns the naturally
        induced coercion between `R'[H]` and `R[G]`. Otherwise
        it returns ``None``.

        EXAMPLES::

            sage: A = GroupAlgebra(SymmetricGroup(4), QQ)
            sage: B = GroupAlgebra(SymmetricGroup(3), ZZ)
            sage: A.has_coerce_map_from(B)
            True
            sage: B.has_coerce_map_from(A)
            False
            sage: A.has_coerce_map_from(ZZ)
            True
            sage: A.has_coerce_map_from(CC)
            False
            sage: A.has_coerce_map_from(SymmetricGroup(5))
            False
            sage: A.has_coerce_map_from(SymmetricGroup(2))
            True


            sage: H = CyclicPermutationGroup(3)
            sage: G = DihedralGroup(3)

            sage: QH = H.algebra(QQ)
            sage: ZH = H.algebra(ZZ)
            sage: QG = G.algebra(QQ)
            sage: ZG = G.algebra(ZZ)
            sage: ZG.coerce_map_from(H)
            Coercion map:
              From: Cyclic group of order 3 as a permutation group
              To:   Algebra of Dihedral group of order 6 as a permutation group over Integer Ring
            sage: QG.coerce_map_from(ZG)
            Generic morphism:
              From: Algebra of Dihedral group of order 6 as a permutation group over Integer Ring
              To:   Algebra of Dihedral group of order 6 as a permutation group over Rational Field
            sage: QG.coerce_map_from(QH)
            Generic morphism:
              From: Algebra of Cyclic group of order 3 as a permutation group over Rational Field
              To:   Algebra of Dihedral group of order 6 as a permutation group over Rational Field
            sage: QG.coerce_map_from(ZH)
            Generic morphism:
              From: Algebra of Cyclic group of order 3 as a permutation group over Integer Ring
              To:   Algebra of Dihedral group of order 6 as a permutation group over Rational Field

        As expected, there is no coercion when restricting the
        field::

            sage: ZG.coerce_map_from(QG)

        This coercion when restricting the group is unexpected::

            sage: QH.coerce_map_from(QG)
            Generic morphism:
              From: Algebra of Dihedral group of order 6 as a permutation group over Rational Field
              To:   Algebra of Cyclic group of order 3 as a permutation group over Rational Field

        but is induced by the partial coercion at the level of
        the groups::

            sage: H.coerce_map_from(G)
            Call morphism:
              From: Dihedral group of order 6 as a permutation group
              To:   Cyclic group of order 3 as a permutation group

        There is no coercion for additive groups since ``+`` could mean
        both the action (i.e., the group operation) or adding a term::

            sage: G = groups.misc.AdditiveCyclic(3)
            sage: ZG = G.algebra(ZZ, category=AdditiveMagmas())
            sage: ZG.has_coerce_map_from(G)
            False
        """
        G = self.basis().keys()
        K = self.base_ring()

        if G.has_coerce_map_from(S):
            from sage.categories.groups import Groups
            # No coercion for additive groups because of ambiguity of +
            #   being the group action or addition of a new term.
            return self.category().is_subcategory(Groups().Algebras(K))

        if S in Sets.Algebras:
            S_K = S.base_ring()
            S_G = S.basis().keys()
            hom_K = K.coerce_map_from(S_K)
            hom_G = G.coerce_map_from(S_G)
            if hom_K is not None and hom_G is not None:
                return SetMorphism(
                    S.Hom(self, category=self.category() | S.category()),
                    lambda x: self.sum_of_terms(
                        (hom_G(g), hom_K(c)) for g, c in x))
Exemple #24
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: ]

            """
            # 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

            # This could be a morphism of Algebras(self.base_ring()); however, e.g., QQ is not in Algebras(QQ)
            H = Hom(base_ring, self, Rings())  # TODO: non associative ring!

            # 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
Exemple #25
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: ]

            """
            # 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
            mor = None
            # This could be a morphism of Algebras(self.base_ring()); however, e.g., QQ is not in Algebras(QQ)
            H = Hom(base_ring, self, Rings())  # TODO: non associative ring!

            # Idea: 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.
            # Hence, if the unit is available *now*, then we store it.
            #
            # However, if there is a specialised from_base_ring method, then it should be used!
            try:
                has_custom_conversion = self.category(
                ).parent_class.from_base_ring.__func__ is not self.from_base_ring.__func__
            except AttributeError:
                # Sometimes from_base_ring is a lazy attribute
                has_custom_conversion = True
            if has_custom_conversion:
                mor = SetMorphism(function=self.from_base_ring, parent=H)
                try:
                    self.register_coercion(mor)
                except AssertionError:
                    pass
                return

            try:
                one = self.one()
            except (NotImplementedError, AttributeError, TypeError):
                # The unit is not available, yet. But there are cases
                # in which it will be available later. Hence:
                mor = SetMorphism(function=self.from_base_ring, parent=H)
            # try sanity of one._lmul_
            if mor is None:
                try:
                    if one._lmul_(base_ring.an_element()) is None:
                        # There are cases in which lmul returns None, believe it or not.
                        # One example: Hecke algebras.
                        # In that case, the generic implementation of from_base_ring would
                        # fail as well. Hence, unless it is overruled, we will not use it.
                        #mor = SetMorphism(function = self.from_base_ring, parent = H)
                        return
                except (NotImplementedError, AttributeError, TypeError):
                    # it is possible that an_element or lmul are not implemented.
                    return
                    #mor = SetMorphism(function = self.from_base_ring, parent = H)
                mor = SetMorphism(function=one._lmul_, parent=H)
            try:
                self.register_coercion(mor)
            except AssertionError:
                pass