Base class for maps¶
AUTHORS:
 Robert Bradshaw: initial implementation
 Sebastien Besnier (2014055):
FormalCompositeMap
contains a list of Map instead of only two Map. See trac ticket #16291.  Sebastian Oehms (20190119):
section()
added toFormalCompositeMap
. See trac ticket #27081.

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.
EXAMPLES:
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

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
EXAMPLES:
sage: f = QQ.coerce_map_from(ZZ) sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) sage: list((g*f).domains()) [Integer Ring, Rational Field]

first
()¶ Return the first map in the formal composition.
If
self
represents \(f_n \circ f_{n1} \circ \cdots \circ f_1 \circ f_0\), thenself.first()
returns \(f_0\). We haveself == self.then() * self.first()
.EXAMPLES:
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.EXAMPLES:
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.EXAMPLES:
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.

section
()¶ Compute a section map from sections of the factors of
self
if they have been implemented.EXAMPLES:
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(pq) 3
the following example has been attached to
_integer_()
ofsage.rings.polynomial.polynomial_element.Polynomial
before (see comment there):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: not a constant polynomial

then
()¶ Return the tail of the list of maps.
If
self
represents \(f_n \circ f_{n1} \circ \cdots \circ f_1 \circ f_0\), thenself.first()
returns \(f_n \circ f_{n1} \circ \cdots \circ f_1\). We haveself == self.then() * self.first()
.EXAMPLES:
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*x1) 1 sage: R.<x,y> = QQ[] sage: f = R.hom([x+y, xy], R) sage: f(x^2+2*x1) 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, xy], R) sage: f.category_for() Join of Category of unique factorization domains 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)
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
EXAMPLES:
sage: 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: 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_surjective
()¶ Tells 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: 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 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: 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 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

post_compose
(left)¶ INPUT:
self
– a Map in someHom(X, Y, category_right)
left
– a Map in someHom(Y, Z, category_left)
Returns the composition of
self
followed byright
as a morphism inHom(X, Z, category)
wherecategory
is the meet ofcategory_left
andcategory_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 someHom(Y, Z, category_left)
left
– a Map in someHom(X, Y, category_right)
Returns the composition of
right
followed byself
as a morphism inHom(X, Z, category)
wherecategory
is the meet ofcategory_left
andcategory_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 returnsNone
. You may override it in subclasses.


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 classSection
.EXAMPLES:
sage: from sage.categories.map import Section sage: R.<x,y> = ZZ[] sage: S.<a,b> = QQ[] sage: f = R.hom([a+b, ab]) 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'>

inverse
()¶ Return inverse of
self
.


sage.categories.map.
is_Map
(x)¶ Auxiliary function: Is the argument a map?
EXAMPLES:
sage: R.<x,y> = QQ[] sage: f = R.hom([x+y, xy], 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.