Base class for maps
AUTHORS:
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
Return the first map in the formal composition.
If self represents , then self.first() returns
. 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
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
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.
Deprecated: Use then() instead. See trac ticket #16291 for details.
Return the tail of the list of maps.
If self represents , then self.first() returns
. 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
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
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 hom sets in Category of rings
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()
Join of Category of hom sets in Category of modules over quotient fields and Category of hom sets in Category of rings
FIXME: find a better name for this method
INPUT:
OUTPUT:
An element of Hom(X, Z) obtained by composing self with . If
no canonical
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
INPUT:
OUTPUT:
An element of Hom(X, Z) obtained by composing self with . If
no canonical
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
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'>
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'>
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 does
not prevent
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
INPUT:
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
INPUT:
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
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
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'>
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
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