Base class for maps - Category Framework

Skip to content
Back to top
View this page
Edit this page

# Base class for maps

AUTHORS:

- Robert Bradshaw: initial implementation

- Sebastien Besnier (2014-05-5): `FormalCompositeMap` contains a list of Map instead of only two Map. See Issue #16291.

- Sebastian Oehms (2019-01-19): `section()` added to `FormalCompositeMap`. See Issue #27081.

class sage.categories.map.FormalCompositeMap

  Bases: `Map`

  Formal composite maps.

  A formal composite map is formed by two maps, so that the codomain of the first map is contained in the domain of the second map.

  Note

  When calling a composite with additional arguments, these arguments are only passed to the second underlying map.

  EXAMPLES:

  Sage

      sage: R.<x> = QQ[]
      sage: S.<a> = QQ[]
      sage: from sage.categories.morphism import SetMorphism
      sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
      sage: g = S.hom([2*x])
      sage: f*g
      Composite map:
        From: Univariate Polynomial Ring in a over Rational Field
        To:   Univariate Polynomial Ring in a over Rational Field
        Defn:   Ring morphism:
                From: Univariate Polynomial Ring in a over Rational Field
                To:   Univariate Polynomial Ring in x over Rational Field
                Defn: a |--> 2*x
              then
                Generic morphism:
                From: Univariate Polynomial Ring in x over Rational Field
                To:   Univariate Polynomial Ring in a over Rational Field
      sage: g*f
      Composite map:
        From: Univariate Polynomial Ring in x over Rational Field
        To:   Univariate Polynomial Ring in x over Rational Field
        Defn:   Generic morphism:
                From: Univariate Polynomial Ring in x over Rational Field
                To:   Univariate Polynomial Ring in a over Rational Field
              then
                Ring morphism:
                From: Univariate Polynomial Ring in a over Rational Field
                To:   Univariate Polynomial Ring in x over Rational Field
                Defn: a |--> 2*x
      sage: (f*g)(2*a^2+5)
      5*a^2
      sage: (g*f)(2*x^2+5)
      20*x^2

  Python

      >>> from sage.all import *
      >>> R = QQ['x']; (x,) = R._first_ngens(1)
      >>> S = QQ['a']; (a,) = S._first_ngens(1)
      >>> from sage.categories.morphism import SetMorphism
      >>> f = SetMorphism(Hom(R, S, Rings()), lambda p: p[Integer(0)]*a**p.degree())
      >>> g = S.hom([Integer(2)*x])
      >>> f*g
      Composite map:
        From: Univariate Polynomial Ring in a over Rational Field
        To:   Univariate Polynomial Ring in a over Rational Field
        Defn:   Ring morphism:
                From: Univariate Polynomial Ring in a over Rational Field
                To:   Univariate Polynomial Ring in x over Rational Field
                Defn: a |--> 2*x
              then
                Generic morphism:
                From: Univariate Polynomial Ring in x over Rational Field
                To:   Univariate Polynomial Ring in a over Rational Field
      >>> g*f
      Composite map:
        From: Univariate Polynomial Ring in x over Rational Field
        To:   Univariate Polynomial Ring in x over Rational Field
        Defn:   Generic morphism:
                From: Univariate Polynomial Ring in x over Rational Field
                To:   Univariate Polynomial Ring in a over Rational Field
              then
                Ring morphism:
                From: Univariate Polynomial Ring in a over Rational Field
                To:   Univariate Polynomial Ring in x over Rational Field
                Defn: a |--> 2*x
      >>> (f*g)(Integer(2)*a**Integer(2)+Integer(5))
      5*a^2
      >>> (g*f)(Integer(2)*x**Integer(2)+Integer(5))
      20*x^2

  domains()

    Iterate over the domains of the factors of this map.

    (This is useful in particular to check for loops in coercion maps.)

    See also

    `Map.domains()`

    EXAMPLES:

    Sage

        sage: f = QQ.coerce_map_from(ZZ)
        sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ)                         # needs sage.modules
        sage: list((g * f).domains())                                               # needs sage.modules
        [Integer Ring, Rational Field]

    Python

        >>> from sage.all import *
        >>> f = QQ.coerce_map_from(ZZ)
        >>> g = MatrixSpace(QQ, Integer(2), Integer(2)).coerce_map_from(QQ)                         # needs sage.modules
        >>> list((g * f).domains())                                               # needs sage.modules
        [Integer Ring, Rational Field]

  first()

    Return the first map in the formal composition.

    If `self` represents \(f_n \circ f_{n-1} \circ \cdots \circ f_1 \circ f_0\), then `self.first()` returns \(f_0\). We have `self == self.then() * self.first()`.

    EXAMPLES:

    Sage

        sage: R.<x> = QQ[]
        sage: S.<a> = QQ[]
        sage: from sage.categories.morphism import SetMorphism
        sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
        sage: g = S.hom([2*x])
        sage: fg = f * g
        sage: fg.first() == g
        True
        sage: fg == fg.then() * fg.first()
        True

    Python

        >>> from sage.all import *
        >>> R = QQ['x']; (x,) = R._first_ngens(1)
        >>> S = QQ['a']; (a,) = S._first_ngens(1)
        >>> from sage.categories.morphism import SetMorphism
        >>> f = SetMorphism(Hom(R, S, Rings()), lambda p: p[Integer(0)]*a**p.degree())
        >>> g = S.hom([Integer(2)*x])
        >>> fg = f * g
        >>> fg.first() == g
        True
        >>> fg == fg.then() * fg.first()
        True

  is_injective()

    Tell whether `self` is injective.

    It raises `NotImplementedError` if it cannot be determined.

    EXAMPLES:

    Sage

        sage: # needs sage.modules
        sage: V1 = QQ^2
        sage: V2 = QQ^3
        sage: phi1 = (QQ^1).hom(Matrix([[1, 1]]), V1)
        sage: phi2 = V1.hom(Matrix([[1, 2, 3], [4, 5, 6]]), V2)

    Python

        >>> from sage.all import *
        >>> # needs sage.modules
        >>> V1 = QQ**Integer(2)
        >>> V2 = QQ**Integer(3)
        >>> phi1 = (QQ**Integer(1)).hom(Matrix([[Integer(1), Integer(1)]]), V1)
        >>> phi2 = V1.hom(Matrix([[Integer(1), Integer(2), Integer(3)], [Integer(4), Integer(5), Integer(6)]]), V2)

    If both constituents are injective, the composition is injective:

    Sage

        sage: from sage.categories.map import FormalCompositeMap
        sage: c1 = FormalCompositeMap(Hom(QQ^1, V2, phi1.category_for()),           # needs sage.modules
        ....:                         phi1, phi2)
        sage: c1.is_injective()                                                     # needs sage.modules
        True

    [Python]

        >>> from sage.all import *
        >>> from sage.categories.map import FormalCompositeMap
        >>> c1 = FormalCompositeMap(Hom(QQ**Integer(1), V2, phi1.category_for()),           # needs sage.modules
        ...                         phi1, phi2)
        >>> c1.is_injective()                                                     # needs sage.modules
        True

    If it cannot be determined whether the composition is injective, an error is raised:

    Sage

        sage: psi1 = V2.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V1)                   # needs sage.modules
        sage: c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()),             # needs sage.modules
        ....:                         phi2, psi1)
        sage: c2.is_injective()                                                     # needs sage.modules
        Traceback (most recent call last):
        ...
        NotImplementedError: not enough information to deduce injectivity

    Python

        >>> from sage.all import *
        >>> psi1 = V2.hom(Matrix([[Integer(1), Integer(2)], [Integer(3), Integer(4)], [Integer(5), Integer(6)]]), V1)                   # needs sage.modules
        >>> c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()),             # needs sage.modules
        ...                         phi2, psi1)
        >>> c2.is_injective()                                                     # needs sage.modules
        Traceback (most recent call last):
        ...
        NotImplementedError: not enough information to deduce injectivity

    If the first map is surjective and the second map is not injective, then the composition is not injective:

    Sage

        sage: psi2 = V1.hom([[1], [1]], QQ^1)                                       # needs sage.modules
        sage: c3 = FormalCompositeMap(Hom(V2, QQ^1, phi2.category_for()),           # needs sage.modules
        ....:                         psi2, psi1)
        sage: c3.is_injective()                                                     # needs sage.modules
        False

    [Python]

        >>> from sage.all import *
        >>> psi2 = V1.hom([[Integer(1)], [Integer(1)]], QQ**Integer(1))                                       # needs sage.modules
        >>> c3 = FormalCompositeMap(Hom(V2, QQ**Integer(1), phi2.category_for()),           # needs sage.modules
        ...                         psi2, psi1)
        >>> c3.is_injective()                                                     # needs sage.modules
        False

  is_surjective()

    Tell whether `self` is surjective.

    It raises `NotImplementedError` if it cannot be determined.

    EXAMPLES:

    Sage

        sage: from sage.categories.map import FormalCompositeMap
        sage: V3 = QQ^3                                                             # needs sage.modules
        sage: V2 = QQ^2                                                             # needs sage.modules
        sage: V1 = QQ^1                                                             # needs sage.modules

    Python

        >>> from sage.all import *
        >>> from sage.categories.map import FormalCompositeMap
        >>> V3 = QQ**Integer(3)                                                             # needs sage.modules
        >>> V2 = QQ**Integer(2)                                                             # needs sage.modules
        >>> V1 = QQ**Integer(1)                                                             # needs sage.modules

    If both maps are surjective, the composition is surjective:

    Sage

        sage: # needs sage.modules
        sage: phi32 = V3.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V2)
        sage: phi21 = V2.hom(Matrix([[1], [1]]), V1)
        sage: c_phi = FormalCompositeMap(Hom(V3, V1, phi32.category_for()),
        ....:                            phi32, phi21)
        sage: c_phi.is_surjective()
        True

    [Python]

        >>> from sage.all import *
        >>> # needs sage.modules
        >>> phi32 = V3.hom(Matrix([[Integer(1), Integer(2)], [Integer(3), Integer(4)], [Integer(5), Integer(6)]]), V2)
        >>> phi21 = V2.hom(Matrix([[Integer(1)], [Integer(1)]]), V1)
        >>> c_phi = FormalCompositeMap(Hom(V3, V1, phi32.category_for()),
        ...                            phi32, phi21)
        >>> c_phi.is_surjective()
        True

    If the second map is not surjective, the composition is not surjective:

    Sage

        sage: FormalCompositeMap(Hom(V3, V1, phi32.category_for()),                 # needs sage.modules
        ....:                    phi32,
        ....:                    V2.hom(Matrix([[0], [0]]), V1)).is_surjective()
        False

    Python

        >>> from sage.all import *
        >>> FormalCompositeMap(Hom(V3, V1, phi32.category_for()),                 # needs sage.modules
        ...                    phi32,
        ...                    V2.hom(Matrix([[Integer(0)], [Integer(0)]]), V1)).is_surjective()
        False

    If the second map is an isomorphism and the first map is not surjective, then the composition is not surjective:

    Sage

        sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()),                 # needs sage.modules
        ....:                    V2.hom(Matrix([[0], [0]]), V1),
        ....:                    V1.hom(Matrix([[1]]), V1)).is_surjective()
        False

    [Python]

        >>> from sage.all import *
        >>> FormalCompositeMap(Hom(V2, V1, phi32.category_for()),                 # needs sage.modules
        ...                    V2.hom(Matrix([[Integer(0)], [Integer(0)]]), V1),
        ...                    V1.hom(Matrix([[Integer(1)]]), V1)).is_surjective()
        False

    Otherwise, surjectivity of the composition cannot be determined:

    Sage

        sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()),                 # needs sage.modules
        ....:     V2.hom(Matrix([[1, 1], [1, 1]]), V2),
        ....:     V2.hom(Matrix([[1], [1]]), V1)).is_surjective()
        Traceback (most recent call last):
        ...
        NotImplementedError: not enough information to deduce surjectivity

    Python

        >>> from sage.all import *
        >>> FormalCompositeMap(Hom(V2, V1, phi32.category_for()),                 # needs sage.modules
        ...     V2.hom(Matrix([[Integer(1), Integer(1)], [Integer(1), Integer(1)]]), V2),
        ...     V2.hom(Matrix([[Integer(1)], [Integer(1)]]), V1)).is_surjective()
        Traceback (most recent call last):
        ...
        NotImplementedError: not enough information to deduce surjectivity

  section()

    Compute a section map from sections of the factors of `self` if they have been implemented.

    EXAMPLES:

    Sage

        sage: P.<x> = QQ[]
        sage: incl = P.coerce_map_from(ZZ)
        sage: sect = incl.section(); sect
        Composite map:
          From: Univariate Polynomial Ring in x over Rational Field
          To:   Integer Ring
          Defn:   Generic map:
                  From: Univariate Polynomial Ring in x over Rational Field
                  To:   Rational Field
                then
                  Generic map:
                  From: Rational Field
                  To:   Integer Ring
        sage: p = x + 5; q = x + 2
        sage: sect(p-q)
        3

    Python

        >>> from sage.all import *
        >>> P = QQ['x']; (x,) = P._first_ngens(1)
        >>> incl = P.coerce_map_from(ZZ)
        >>> sect = incl.section(); sect
        Composite map:
          From: Univariate Polynomial Ring in x over Rational Field
          To:   Integer Ring
          Defn:   Generic map:
                  From: Univariate Polynomial Ring in x over Rational Field
                  To:   Rational Field
                then
                  Generic map:
                  From: Rational Field
                  To:   Integer Ring
        >>> p = x + Integer(5); q = x + Integer(2)
        >>> sect(p-q)
        3

    the following example has been attached to `_integer_()` of `sage.rings.polynomial.polynomial_element.Polynomial` before (see comment there):

    Sage

        sage: k = GF(47)
        sage: R.<x> = PolynomialRing(k)
        sage: R.coerce_map_from(ZZ).section()
        Composite map:
          From: Univariate Polynomial Ring in x over Finite Field of size 47
          To:   Integer Ring
          Defn:   Generic map:
                  From: Univariate Polynomial Ring in x over Finite Field of size 47
                  To:   Finite Field of size 47
                then
                  Lifting map:
                  From: Finite Field of size 47
                  To:   Integer Ring
        sage: ZZ(R(45))                 # indirect doctest
        45
        sage: ZZ(3*x + 45)              # indirect doctest
        Traceback (most recent call last):
        ...
        TypeError: 3*x + 45 is not a constant polynomial

    [Python]

        >>> from sage.all import *
        >>> k = GF(Integer(47))
        >>> R = PolynomialRing(k, names=('x',)); (x,) = R._first_ngens(1)
        >>> R.coerce_map_from(ZZ).section()
        Composite map:
          From: Univariate Polynomial Ring in x over Finite Field of size 47
          To:   Integer Ring
          Defn:   Generic map:
                  From: Univariate Polynomial Ring in x over Finite Field of size 47
                  To:   Finite Field of size 47
                then
                  Lifting map:
                  From: Finite Field of size 47
                  To:   Integer Ring
        >>> ZZ(R(Integer(45)))                 # indirect doctest
        45
        >>> ZZ(Integer(3)*x + Integer(45))              # indirect doctest
        Traceback (most recent call last):
        ...
        TypeError: 3*x + 45 is not a constant polynomial

  then()

    Return the tail of the list of maps.

    If `self` represents \(f_n \circ f_{n-1} \circ \cdots \circ f_1 \circ f_0\), then `self.first()` returns \(f_n \circ f_{n-1} \circ \cdots \circ f_1\). We have `self == self.then() * self.first()`.

    EXAMPLES:

    Sage

        sage: R.<x> = QQ[]
        sage: S.<a> = QQ[]
        sage: from sage.categories.morphism import SetMorphism
        sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
        sage: g = S.hom([2*x])
        sage: (f*g).then() == f
        True

        sage: f = QQ.coerce_map_from(ZZ)
        sage: f = f.extend_domain(ZZ).extend_codomain(QQ)
        sage: f.then()
        Composite map:
        From: Integer Ring
        To:   Rational Field
        Defn:   Natural morphism:
        From: Integer Ring
        To:   Rational Field
        then
        Identity endomorphism of Rational Field

    Python

        >>> from sage.all import *
        >>> R = QQ['x']; (x,) = R._first_ngens(1)
        >>> S = QQ['a']; (a,) = S._first_ngens(1)
        >>> from sage.categories.morphism import SetMorphism
        >>> f = SetMorphism(Hom(R, S, Rings()), lambda p: p[Integer(0)]*a**p.degree())
        >>> g = S.hom([Integer(2)*x])
        >>> (f*g).then() == f
        True

        >>> f = QQ.coerce_map_from(ZZ)
        >>> f = f.extend_domain(ZZ).extend_codomain(QQ)
        >>> f.then()
        Composite map:
        From: Integer Ring
        To:   Rational Field
        Defn:   Natural morphism:
        From: Integer Ring
        To:   Rational Field
        then
        Identity endomorphism of Rational Field

class sage.categories.map.Map

  Bases: `Element`

  Basic class for all maps.

  Note

  The call method is of course not implemented in this base class. This must be done in the sub classes, by overloading `_call_` and possibly also `_call_with_args`.

  EXAMPLES:

  Usually, instances of this class will not be constructed directly, but for example like this:

  Sage

      sage: from sage.categories.morphism import SetMorphism
      sage: X.<x> = ZZ[]
      sage: Y = ZZ
      sage: phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
      sage: phi(x^2+2*x-1)
      -1
      sage: R.<x,y> = QQ[]
      sage: f = R.hom([x+y, x-y], R)
      sage: f(x^2+2*x-1)
      x^2 + 2*x*y + y^2 + 2*x + 2*y - 1

  Python

      >>> from sage.all import *
      >>> from sage.categories.morphism import SetMorphism
      >>> X = ZZ['x']; (x,) = X._first_ngens(1)
      >>> Y = ZZ
      >>> phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[Integer(0)])
      >>> phi(x**Integer(2)+Integer(2)*x-Integer(1))
      -1
      >>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
      >>> f = R.hom([x+y, x-y], R)
      >>> f(x**Integer(2)+Integer(2)*x-Integer(1))
      x^2 + 2*x*y + y^2 + 2*x + 2*y - 1

  category_for()

    Return the category `self` is a morphism for.

    Note

    This is different from the category of maps to which this map belongs as an object.

    EXAMPLES:

    Sage

        sage: from sage.categories.morphism import SetMorphism
        sage: X.<x> = ZZ[]
        sage: Y = ZZ
        sage: phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
        sage: phi.category_for()
        Category of rings
        sage: phi.category()
        Category of homsets of unital magmas and additive unital additive magmas
        sage: R.<x,y> = QQ[]
        sage: f = R.hom([x+y, x-y], R)
        sage: f.category_for()
        Join of Category of unique factorization domains
         and Category of algebras with basis over
          (number fields and quotient fields and metric spaces)
         and Category of commutative algebras over
          (number fields and quotient fields and metric spaces)
         and Category of infinite sets
        sage: f.category()
        Category of endsets of unital magmas
         and right modules over (number fields and quotient fields and metric spaces)
         and left modules over (number fields and quotient fields and metric spaces)

    Python

        >>> from sage.all import *
        >>> from sage.categories.morphism import SetMorphism
        >>> X = ZZ['x']; (x,) = X._first_ngens(1)
        >>> Y = ZZ
        >>> phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[Integer(0)])
        >>> phi.category_for()
        Category of rings
        >>> phi.category()
        Category of homsets of unital magmas and additive unital additive magmas
        >>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
        >>> f = R.hom([x+y, x-y], R)
        >>> f.category_for()
        Join of Category of unique factorization domains
         and Category of algebras with basis over
          (number fields and quotient fields and metric spaces)
         and Category of commutative algebras over
          (number fields and quotient fields and metric spaces)
         and Category of infinite sets
        >>> f.category()
        Category of endsets of unital magmas
         and right modules over (number fields and quotient fields and metric spaces)
         and left modules over (number fields and quotient fields and metric spaces)

    FIXME: find a better name for this method

  codomain
  domain
  domains()

    Iterate over the domains of the factors of a (composite) map.

    This default implementation simply yields the domain of this map.

    See also

    `FormalCompositeMap.domains()`

    EXAMPLES:

    Sage

        sage: list(QQ.coerce_map_from(ZZ).domains())
        [Integer Ring]

    Python

        >>> from sage.all import *
        >>> list(QQ.coerce_map_from(ZZ).domains())
        [Integer Ring]

  extend_codomain(new_codomain)

    INPUT:

    - `self` – a member of Hom(X, Y)

    - `new_codomain` – an object Z such that there is a canonical coercion \(\phi\) in Hom(Y, Z)

    OUTPUT:

    An element of Hom(X, Z) obtained by composing `self` with \(\phi\). If no canonical \(\phi\) exists, a `TypeError` is raised.

    EXAMPLES:

    Sage

        sage: mor = QQ.coerce_map_from(ZZ)
        sage: mor.extend_codomain(RDF)
        Composite map:
          From: Integer Ring
          To:   Real Double Field
          Defn:   Natural morphism:
                  From: Integer Ring
                  To:   Rational Field
                then
                  Native morphism:
                  From: Rational Field
                  To:   Real Double Field
        sage: mor.extend_codomain(GF(7))
        Traceback (most recent call last):
        ...
        TypeError: No coercion from Rational Field to Finite Field of size 7

    Python

        >>> from sage.all import *
        >>> mor = QQ.coerce_map_from(ZZ)
        >>> mor.extend_codomain(RDF)
        Composite map:
          From: Integer Ring
          To:   Real Double Field
          Defn:   Natural morphism:
                  From: Integer Ring
                  To:   Rational Field
                then
                  Native morphism:
                  From: Rational Field
                  To:   Real Double Field
        >>> mor.extend_codomain(GF(Integer(7)))
        Traceback (most recent call last):
        ...
        TypeError: No coercion from Rational Field to Finite Field of size 7

  extend_domain(new_domain)

    INPUT:

    - `self` – a member of Hom(Y, Z)

    - `new_codomain` – an object X such that there is a canonical coercion \(\phi\) in Hom(X, Y)

    OUTPUT:

    An element of Hom(X, Z) obtained by composing self with \(\phi\). If no canonical \(\phi\) exists, a `TypeError` is raised.

    EXAMPLES:

    Sage

        sage: # needs sage.rings.complex_double
        sage: mor = CDF.coerce_map_from(RDF)
        sage: mor.extend_domain(QQ)
        Composite map:
          From: Rational Field
          To:   Complex Double Field
          Defn:   Native morphism:
                  From: Rational Field
                  To:   Real Double Field
                then
                  Native morphism:
                  From: Real Double Field
                  To:   Complex Double Field
        sage: mor.extend_domain(ZZ['x'])
        Traceback (most recent call last):
        ...
        TypeError: No coercion from Univariate Polynomial Ring in x over Integer Ring
        to Real Double Field

    Python

        >>> from sage.all import *
        >>> # needs sage.rings.complex_double
        >>> mor = CDF.coerce_map_from(RDF)
        >>> mor.extend_domain(QQ)
        Composite map:
          From: Rational Field
          To:   Complex Double Field
          Defn:   Native morphism:
                  From: Rational Field
                  To:   Real Double Field
                then
                  Native morphism:
                  From: Real Double Field
                  To:   Complex Double Field
        >>> mor.extend_domain(ZZ['x'])
        Traceback (most recent call last):
        ...
        TypeError: No coercion from Univariate Polynomial Ring in x over Integer Ring
        to Real Double Field

  is_surjective()

    Tell whether the map is surjective (not implemented in the base class).

  parent()

    Return the homset containing this map.

    Note

    The method `_make_weak_references()`, that is used for the maps found by the coercion system, needs to remove the usual strong reference from the coercion map to the homset containing it. As long as the user keeps strong references to domain and codomain of the map, we will be able to reconstruct the homset. However, a strong reference to the coercion map does not prevent the domain from garbage collection!

    EXAMPLES:

    Sage

        sage: Q = QuadraticField(-5)                                                # needs sage.rings.number_field
        sage: phi = CDF._internal_convert_map_from(Q)                               # needs sage.rings.number_field
        sage: print(phi.parent())                                                   # needs sage.rings.number_field
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field

    Python

        >>> from sage.all import *
        >>> Q = QuadraticField(-Integer(5))                                                # needs sage.rings.number_field
        >>> phi = CDF._internal_convert_map_from(Q)                               # needs sage.rings.number_field
        >>> print(phi.parent())                                                   # needs sage.rings.number_field
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field

    We now demonstrate that the reference to the coercion map \(\phi\) does not prevent \(Q\) from being garbage collected:

    Sage

        sage: import gc
        sage: del Q                                                                 # needs sage.rings.number_field
        sage: _ = gc.collect()
        sage: phi.parent()                                                          # needs sage.rings.number_field
        Traceback (most recent call last):
        ...
        ValueError: This map is in an invalid state,
        the domain has been garbage collected

    [Python]

        >>> from sage.all import *
        >>> import gc
        >>> del Q                                                                 # needs sage.rings.number_field
        >>> _ = gc.collect()
        >>> phi.parent()                                                          # needs sage.rings.number_field
        Traceback (most recent call last):
        ...
        ValueError: This map is in an invalid state,
        the domain has been garbage collected

    You can still obtain copies of the maps used by the coercion system with strong references:

    Sage

        sage: # needs sage.rings.number_field
        sage: Q = QuadraticField(-5)
        sage: phi = CDF.convert_map_from(Q)
        sage: print(phi.parent())
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field
        sage: import gc
        sage: del Q
        sage: _ = gc.collect()
        sage: phi.parent()
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field

    Python

        >>> from sage.all import *
        >>> # needs sage.rings.number_field
        >>> Q = QuadraticField(-Integer(5))
        >>> phi = CDF.convert_map_from(Q)
        >>> print(phi.parent())
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field
        >>> import gc
        >>> del Q
        >>> _ = gc.collect()
        >>> phi.parent()
        Set of field embeddings
         from Number Field in a with defining polynomial x^2 + 5
              with a = 2.236067977499790?*I
           to Complex Double Field

  post_compose(left)

    INPUT:

    - `self` – a Map in some `Hom(X, Y, category_right)`

    - `left` – a Map in some `Hom(Y, Z, category_left)`

    Returns the composition of `self` followed by `left` as a morphism in `Hom(X, Z, category)` where `category` is the meet of `category_left` and `category_right`.

    Caveat: see the current restrictions on `Category.meet()`

    EXAMPLES:

    Sage

        sage: from sage.categories.morphism import SetMorphism
        sage: X.<x> = ZZ[]
        sage: Y = ZZ
        sage: Z = QQ
        sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
        sage: phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**2))
        sage: phi_xz = phi_xy.post_compose(phi_yz); phi_xz
        Composite map:
          From: Univariate Polynomial Ring in x over Integer Ring
          To:   Rational Field
          Defn:   Generic morphism:
                  From: Univariate Polynomial Ring in x over Integer Ring
                  To:   Integer Ring
                then
                  Generic morphism:
                  From: Integer Ring
                  To:   Rational Field
        sage: phi_xz.category_for()
        Category of monoids

    Python

        >>> from sage.all import *
        >>> from sage.categories.morphism import SetMorphism
        >>> X = ZZ['x']; (x,) = X._first_ngens(1)
        >>> Y = ZZ
        >>> Z = QQ
        >>> phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[Integer(0)])
        >>> phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**Integer(2)))
        >>> phi_xz = phi_xy.post_compose(phi_yz); phi_xz
        Composite map:
          From: Univariate Polynomial Ring in x over Integer Ring
          To:   Rational Field
          Defn:   Generic morphism:
                  From: Univariate Polynomial Ring in x over Integer Ring
                  To:   Integer Ring
                then
                  Generic morphism:
                  From: Integer Ring
                  To:   Rational Field
        >>> phi_xz.category_for()
        Category of monoids

  pre_compose(right)

    INPUT:

    - `self` – a Map in some `Hom(Y, Z, category_left)`

    - `left` – a Map in some `Hom(X, Y, category_right)`

    Returns the composition of `right` followed by `self` as a morphism in `Hom(X, Z, category)` where `category` is the meet of `category_left` and `category_right`.

    EXAMPLES:

    Sage

        sage: from sage.categories.morphism import SetMorphism
        sage: X.<x> = ZZ[]
        sage: Y = ZZ
        sage: Z = QQ
        sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
        sage: phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**2))
        sage: phi_xz = phi_yz.pre_compose(phi_xy); phi_xz
        Composite map:
          From: Univariate Polynomial Ring in x over Integer Ring
          To:   Rational Field
          Defn:   Generic morphism:
                  From: Univariate Polynomial Ring in x over Integer Ring
                  To:   Integer Ring
                then
                  Generic morphism:
                  From: Integer Ring
                  To:   Rational Field
        sage: phi_xz.category_for()
        Category of monoids

    Python

        >>> from sage.all import *
        >>> from sage.categories.morphism import SetMorphism
        >>> X = ZZ['x']; (x,) = X._first_ngens(1)
        >>> Y = ZZ
        >>> Z = QQ
        >>> phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[Integer(0)])
        >>> phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**Integer(2)))
        >>> phi_xz = phi_yz.pre_compose(phi_xy); phi_xz
        Composite map:
          From: Univariate Polynomial Ring in x over Integer Ring
          To:   Rational Field
          Defn:   Generic morphism:
                  From: Univariate Polynomial Ring in x over Integer Ring
                  To:   Integer Ring
                then
                  Generic morphism:
                  From: Integer Ring
                  To:   Rational Field
        >>> phi_xz.category_for()
        Category of monoids

  section()

    Return a section of `self`.

    Note

    By default, it returns `None`. You may override it in subclasses.

class sage.categories.map.Section

  Bases: `Map`

  A formal section of a map.

  Note

  Call methods are not implemented for the base class `Section`.

  EXAMPLES:

  Sage

      sage: from sage.categories.map import Section
      sage: R.<x,y> = ZZ[]
      sage: S.<a,b> = QQ[]
      sage: f = R.hom([a+b, a-b])
      sage: sf = Section(f); sf
      Section map:
        From: Multivariate Polynomial Ring in a, b over Rational Field
        To:   Multivariate Polynomial Ring in x, y over Integer Ring
      sage: sf(a)
      Traceback (most recent call last):
      ...
      NotImplementedError: <class 'sage.categories.map.Section'>

  Python

      >>> from sage.all import *
      >>> from sage.categories.map import Section
      >>> R = ZZ['x, y']; (x, y,) = R._first_ngens(2)
      >>> S = QQ['a, b']; (a, b,) = S._first_ngens(2)
      >>> f = R.hom([a+b, a-b])
      >>> sf = Section(f); sf
      Section map:
        From: Multivariate Polynomial Ring in a, b over Rational Field
        To:   Multivariate Polynomial Ring in x, y over Integer Ring
      >>> sf(a)
      Traceback (most recent call last):
      ...
      NotImplementedError: <class 'sage.categories.map.Section'>

  inverse()

    Return inverse of `self`.

sage.categories.map.is_Map(x)

  Auxiliary function: Is the argument a map?

  EXAMPLES:

  Sage

      sage: R.<x,y> = QQ[]
      sage: f = R.hom([x+y, x-y], R)
      sage: from sage.categories.map import is_Map
      sage: is_Map(f)
      doctest:warning...
      DeprecationWarning: The function is_Map is deprecated; use 'isinstance(..., Map)' instead.
      See https://github.com/sagemath/sage/issues/38103 for details.
      True

  Python

      >>> from sage.all import *
      >>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
      >>> f = R.hom([x+y, x-y], R)
      >>> from sage.categories.map import is_Map
      >>> is_Map(f)
      doctest:warning...
      DeprecationWarning: The function is_Map is deprecated; use 'isinstance(..., Map)' instead.
      See https://github.com/sagemath/sage/issues/38103 for details.
      True

sage.categories.map.unpickle_map(_class, parent, _dict, _slots)

  Auxiliary function for unpickling a map.