### Navigation

- index
- modules |
- next |
- previous |
- Category Theory »

# Base class for maps

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 trac ticket #16291.

class `sage.categories.map.``FormalCompositeMap`

  Bases: `sage.categories.map.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.

  EXAMPLE:

      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

  `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()`.

    EXAMPLE:

        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

  `is_injective`()

    Tell whether `self` is injective.

    It raises `NotImplementedError` if it can’t be determined.

    EXAMPLE:

        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)

    If both constituents are injective, the composition is injective:

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

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

        sage: psi1 = V2.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V1)
        sage: c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()), phi2, psi1)
        sage: c2.is_injective()
        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: psi2 = V1.hom([[1], [1]], QQ^1)
        sage: c3 = FormalCompositeMap(Hom(V2, QQ^1, phi2.category_for()), psi2, psi1)
        sage: c3.is_injective()
        False

  `is_surjective`()

    Tell whether `self` is surjective.

    It raises `NotImplementedError` if it can’t be determined.

    EXAMPLE:

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

    If both maps are surjective, the composition is surjective:

        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

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

        sage: FormalCompositeMap(Hom(V3, V1, phi32.category_for()), phi32, V2.hom(Matrix([[0], [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: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), V2.hom(Matrix([[0], [0]]), V1), V1.hom(Matrix([[1]]), V1)).is_surjective()
        False

    Otherwise, surjectivity of the composition cannot be determined:

        sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()),
        ...     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.

  `second`(*args, **kwds)

    Deprecated: Use `then()` instead. See trac ticket #16291 for details.

  `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()`.

    EXAMPLE:

        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

class `sage.categories.map.``Map`

  Bases: `sage.structure.element.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: 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

  `category_for`()

    Returns 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: 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 commutative algebras over quotient fields
        sage: f.category()
        Category of endsets of unital magmas and right modules over quotient fields and left modules over quotient fields

    FIXME: find a better name for this method

  `codomain`
  `domain`
  `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: 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

  `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: 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

  `is_injective`()

    Tells whether the map is injective (not implemented in the base class).

    TEST:

        sage: from sage.categories.map import Map
        sage: f = Map(Hom(QQ, ZZ, Rings()))
        sage: f.is_injective()
        Traceback (most recent call last):
        ...
        NotImplementedError: <type 'sage.categories.map.Map'>

  `is_surjective`()

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

    TEST:

        sage: from sage.categories.map import Map
        sage: f = Map(Hom(QQ, ZZ, Rings()))
        sage: f.is_surjective()
        Traceback (most recent call last):
        ...
        NotImplementedError: <type 'sage.categories.map.Map'>

  `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: Q = QuadraticField(-5)
        sage: phi = CDF._internal_convert_map_from(Q)
        sage: print phi.parent()
        Set of field embeddings from Number Field in a with defining polynomial x^2 + 5 to Complex Double Field

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

        sage: import gc
        sage: del Q
        sage: _ = gc.collect()
        sage: phi.parent()
        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: 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 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 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 `right` 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: 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

  `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: 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

  `section`()

    Return a section of self.

    NOTE:

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

    TEST:

        sage: R.<x,y> = QQ[]
        sage: f = R.hom([x+y, x-y], R)
        sage: print f.section()
        None

        sage: f = QQ.coerce_map_from(ZZ); f
        Natural morphism:
          From: Integer Ring
          To:   Rational Field
        sage: ff = f.section(); ff
        Generic map:
          From: Rational Field
          To:   Integer Ring
        sage: ff(4/2)
        2
        sage: parent(ff(4/2)) is ZZ
        True
        sage: ff(1/2)
        Traceback (most recent call last):
        ...
        TypeError: no conversion of this rational to integer

class `sage.categories.map.``Section`

  Bases: `sage.categories.map.Map`

  A formal section of a map.

  NOTE:

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

  EXAMPLE:

      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: <type 'sage.categories.map.Section'>

`sage.categories.map.``is_Map`(x)

  Auxiliary function: Is the argument a map?

  EXAMPLE:

      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)
      True

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

  Auxiliary function for unpickling a map.

  TEST:

      sage: R.<x,y> = QQ[]
      sage: f = R.hom([x+y, x-y], R)
      sage: f == loads(dumps(f))  # indirect doctest
      True

### Navigation

- index
- modules |
- next |
- previous |
- Category Theory »