Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/generic/homset.py
8820 views
1
r"""
2
Set of homomorphisms between two schemes
3
4
For schemes `X` and `Y`, this module implements the set of morphisms
5
`Hom(X,Y)`. This is done by :class:`SchemeHomset_generic`.
6
7
As a special case, the Hom-sets can also represent the points of a
8
scheme. Recall that the `K`-rational points of a scheme `X` over `k`
9
can be identified with the set of morphisms `Spec(K) \to X`. In Sage
10
the rational points are implemented by such scheme morphisms. This is
11
done by :class:`SchemeHomset_points` and its subclasses.
12
13
.. note::
14
15
You should not create the Hom-sets manually. Instead, use the
16
:meth:`~sage.structure.parent.Hom` method that is inherited by all
17
schemes.
18
19
AUTHORS:
20
21
- William Stein (2006): initial version.
22
23
- Volker Braun (2011-08-11): significant improvement and refactoring.
24
25
- Ben Hutz (June 2012): added support for projective ring
26
"""
27
28
29
#*****************************************************************************
30
# Copyright (C) 2011 Volker Braun <[email protected]>
31
# Copyright (C) 2006 William Stein <[email protected]>
32
#
33
# Distributed under the terms of the GNU General Public License (GPL)
34
# as published by the Free Software Foundation; either version 2 of
35
# the License, or (at your option) any later version.
36
# http://www.gnu.org/licenses/
37
#*****************************************************************************
38
39
40
from sage.categories.homset import HomsetWithBase
41
from sage.structure.factory import UniqueFactory
42
43
from sage.rings.all import ( gcd, ZZ, QQ )
44
45
from sage.rings.morphism import is_RingHomomorphism
46
from sage.rings.rational_field import is_RationalField
47
from sage.rings.finite_rings.constructor import is_FiniteField
48
from sage.rings.commutative_ring import is_CommutativeRing
49
50
51
from sage.schemes.generic.scheme import is_Scheme
52
from sage.schemes.generic.spec import Spec, is_Spec
53
from sage.schemes.generic.morphism import (
54
SchemeMorphism,
55
SchemeMorphism_structure_map,
56
SchemeMorphism_spec )
57
58
59
def is_SchemeHomset(H):
60
r"""
61
Test whether ``H`` is a scheme Hom-set.
62
63
EXAMPLES::
64
65
sage: f = Spec(QQ).identity_morphism(); f
66
Scheme endomorphism of Spectrum of Rational Field
67
Defn: Identity map
68
sage: from sage.schemes.generic.homset import is_SchemeHomset
69
sage: is_SchemeHomset(f)
70
False
71
sage: is_SchemeHomset(f.parent())
72
True
73
sage: is_SchemeHomset('a string')
74
False
75
"""
76
return isinstance(H, SchemeHomset_generic)
77
78
79
#*******************************************************************
80
# Factory for Hom sets of schemes
81
#*******************************************************************
82
class SchemeHomsetFactory(UniqueFactory):
83
"""
84
Factory for Hom-sets of schemes.
85
86
EXAMPLES::
87
88
sage: A2 = AffineSpace(QQ,2)
89
sage: A3 = AffineSpace(QQ,3)
90
sage: Hom = A3.Hom(A2)
91
92
The Hom-sets are unique::
93
94
sage: Hom is copy(Hom)
95
True
96
sage: Hom is A3.Hom(A2)
97
True
98
sage: loads(Hom.dumps()) is Hom
99
True
100
101
Here is a tricky point. The Hom-sets are not identical if
102
domains/codomains are isomorphic but not identiacal::
103
104
sage: A3_iso = AffineSpace(QQ,3)
105
sage: [ A3_iso is A3, A3_iso == A3 ]
106
[False, True]
107
sage: Hom_iso = A3_iso.Hom(A2)
108
sage: Hom_iso is Hom
109
False
110
sage: Hom_iso == Hom
111
True
112
113
TESTS::
114
115
sage: Hom.base()
116
Integer Ring
117
sage: Hom.base_ring()
118
Integer Ring
119
"""
120
121
def create_key_and_extra_args(self, X, Y, category=None, base=ZZ,
122
check=True):
123
"""
124
Create a key that uniquely determines the Hom-set.
125
126
INPUT:
127
128
- ``X`` -- a scheme. The domain of the morphisms.
129
130
- ``Y`` -- a scheme. The codomain of the morphisms.
131
132
- ``category`` -- a category for the Hom-sets (default: schemes over
133
given base).
134
135
- ``base`` -- a scheme or a ring. The base scheme of domain
136
and codomain schemes. If a ring is specified, the spectrum
137
of that ring will be used as base scheme.
138
139
- ``check`` -- boolean (default: ``True``).
140
141
EXAMPLES::
142
143
sage: A2 = AffineSpace(QQ,2)
144
sage: A3 = AffineSpace(QQ,3)
145
sage: A3.Hom(A2) # indirect doctest
146
Set of morphisms
147
From: Affine Space of dimension 3 over Rational Field
148
To: Affine Space of dimension 2 over Rational Field
149
sage: from sage.schemes.generic.homset import SchemeHomsetFactory
150
sage: SHOMfactory = SchemeHomsetFactory('test')
151
sage: key, extra = SHOMfactory.create_key_and_extra_args(A3,A2,check=False)
152
sage: key
153
(..., ..., Category of schemes over Integer Ring)
154
sage: extra
155
{'Y': Affine Space of dimension 2 over Rational Field,
156
'X': Affine Space of dimension 3 over Rational Field,
157
'base_ring': Integer Ring, 'check': False}
158
"""
159
if not is_Scheme(X) and is_CommutativeRing(X):
160
X = Spec(X)
161
if not is_Scheme(Y) and is_CommutativeRing(Y):
162
Y = Spec(Y)
163
if is_Spec(base):
164
base_spec = base
165
base_ring = base.coordinate_ring()
166
elif is_CommutativeRing(base):
167
base_spec = Spec(base)
168
base_ring = base
169
else:
170
raise ValueError(
171
'The base must be a commutative ring or its spectrum.')
172
if not category:
173
from sage.categories.schemes import Schemes
174
category = Schemes(base_spec)
175
key = tuple([id(X), id(Y), category])
176
extra = {'X':X, 'Y':Y, 'base_ring':base_ring, 'check':check}
177
return key, extra
178
179
def create_object(self, version, key, **extra_args):
180
"""
181
Create a :class:`SchemeHomset_generic`.
182
183
INPUT:
184
185
- ``version`` -- object version. Currently not used.
186
187
- ``key`` -- a key created by :meth:`create_key_and_extra_args`.
188
189
- ``extra_args`` -- a dictionary of extra keyword arguments.
190
191
EXAMPLES::
192
193
sage: A2 = AffineSpace(QQ,2)
194
sage: A3 = AffineSpace(QQ,3)
195
sage: A3.Hom(A2) is A3.Hom(A2) # indirect doctest
196
True
197
sage: from sage.schemes.generic.homset import SchemeHomsetFactory
198
sage: SHOMfactory = SchemeHomsetFactory('test')
199
sage: SHOMfactory.create_object(0, [id(A3),id(A2),A3.category()], check=True,
200
... X=A3, Y=A2, base_ring=QQ)
201
Set of morphisms
202
From: Affine Space of dimension 3 over Rational Field
203
To: Affine Space of dimension 2 over Rational Field
204
"""
205
category = key[2]
206
X = extra_args.pop('X')
207
Y = extra_args.pop('Y')
208
base_ring = extra_args.pop('base_ring')
209
if is_Spec(X):
210
return Y._point_homset(X, Y, category=category, base=base_ring, **extra_args)
211
try:
212
return X._homset(X, Y, category=category, base=base_ring, **extra_args)
213
except AttributeError:
214
return SchemeHomset_generic(X, Y, category=category, base=base_ring, **extra_args)
215
216
217
SchemeHomset = SchemeHomsetFactory('sage.schemes.generic.homset.SchemeHomset')
218
219
220
221
#*******************************************************************
222
# Base class
223
#*******************************************************************
224
class SchemeHomset_generic(HomsetWithBase):
225
r"""
226
The base class for Hom-sets of schemes.
227
228
INPUT:
229
230
- ``X`` -- a scheme. The domain of the Hom-set.
231
232
- ``Y`` -- a scheme. The codomain of the Hom-set.
233
234
- ``category`` -- a category (optional). The category of the
235
Hom-set.
236
237
- ``check`` -- boolean (optional, default=``True``). Whether to
238
check the defining data for consistency.
239
240
EXAMPLES::
241
242
sage: from sage.schemes.generic.homset import SchemeHomset_generic
243
sage: A2 = AffineSpace(QQ,2)
244
sage: Hom = SchemeHomset_generic(A2, A2); Hom
245
Set of morphisms
246
From: Affine Space of dimension 2 over Rational Field
247
To: Affine Space of dimension 2 over Rational Field
248
sage: Hom.category()
249
Category of hom sets in Category of Schemes
250
"""
251
Element = SchemeMorphism
252
253
def __call__(self, *args, **kwds):
254
r"""
255
Make Hom-sets callable.
256
257
See the ``_call_()`` method of the derived class. All
258
arguments are handed through.
259
260
EXAMPLES::
261
262
sage: A2 = AffineSpace(QQ,2)
263
sage: A2(4,5)
264
(4, 5)
265
"""
266
# Homset (base of HomsetWithBase) overrides __call__ @#$
267
from sage.structure.parent import Set_generic
268
return Set_generic.__call__(self, *args, **kwds)
269
270
def _repr_(self):
271
r"""
272
Return a string representation.
273
274
OUTPUT:
275
276
A string.
277
278
EXAMPLES::
279
280
sage: A = AffineSpace(4, QQ)
281
sage: print A.structure_morphism()._repr_()
282
Scheme morphism:
283
From: Affine Space of dimension 4 over Rational Field
284
To: Spectrum of Rational Field
285
Defn: Structure map
286
"""
287
s = 'Set of morphisms'
288
s += '\n From: %s' % self.domain()
289
s += '\n To: %s' % self.codomain()
290
return s
291
292
def natural_map(self):
293
r"""
294
Return a natural map in the Hom space.
295
296
OUTPUT:
297
298
A :class:`SchemeMorphism` if there is a natural map from
299
domain to codomain. Otherwise, a ``NotImplementedError`` is
300
raised.
301
302
EXAMPLES::
303
304
sage: A = AffineSpace(4, QQ)
305
sage: A.structure_morphism() # indirect doctest
306
Scheme morphism:
307
From: Affine Space of dimension 4 over Rational Field
308
To: Spectrum of Rational Field
309
Defn: Structure map
310
"""
311
X = self.domain()
312
Y = self.codomain()
313
if is_Spec(Y) and Y.coordinate_ring() == X.base_ring():
314
return SchemeMorphism_structure_map(self)
315
raise NotImplementedError
316
317
def _element_constructor_(self, x, check=True):
318
"""
319
Construct a scheme morphism.
320
321
INPUT:
322
323
- `x` -- a ring morphism, or a list or a tuple that define a
324
ring morphism.
325
326
- ``check`` -- boolean (default: ``True``) passed onto
327
functions called by this one to be more careful about input
328
argument type checking.
329
330
EXAMPLES::
331
332
sage: f = ZZ.hom(QQ); f
333
Ring Coercion morphism:
334
From: Integer Ring
335
To: Rational Field
336
337
sage: H = Hom(Spec(QQ, ZZ), Spec(ZZ)); H
338
Set of rational points of Spectrum of Integer Ring
339
340
sage: phi = H(f); phi
341
Affine Scheme morphism:
342
From: Spectrum of Rational Field
343
To: Spectrum of Integer Ring
344
Defn: Ring Coercion morphism:
345
From: Integer Ring
346
To: Rational Field
347
348
TESTS::
349
350
sage: H._element_constructor_(f)
351
Affine Scheme morphism:
352
From: Spectrum of Rational Field
353
To: Spectrum of Integer Ring
354
Defn: Ring Coercion morphism:
355
From: Integer Ring
356
To: Rational Field
357
358
We illustrate input type checking::
359
360
sage: R.<x,y> = QQ[]
361
sage: A.<x,y> = AffineSpace(R)
362
sage: C = A.subscheme(x*y-1)
363
sage: H = C.Hom(C); H
364
Set of morphisms
365
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
366
x*y - 1
367
To: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
368
x*y - 1
369
sage: H(1)
370
Traceback (most recent call last):
371
...
372
TypeError: x must be a ring homomorphism, list or tuple
373
"""
374
if isinstance(x, (list, tuple)):
375
return self.domain()._morphism(self, x, check=check)
376
377
if is_RingHomomorphism(x):
378
return SchemeMorphism_spec(self, x, check=check)
379
380
raise TypeError, "x must be a ring homomorphism, list or tuple"
381
382
383
#*******************************************************************
384
# Base class for points
385
#*******************************************************************
386
class SchemeHomset_points(SchemeHomset_generic):
387
"""
388
Set of rational points of the scheme.
389
390
Recall that the `K`-rational points of a scheme `X` over `k` can
391
be identified with the set of morphisms `Spec(K) \to X`. In Sage,
392
the rational points are implemented by such scheme morphisms.
393
394
If a scheme has a finite number of points, then the homset is
395
supposed to implement the Python iterator interface. See
396
:class:`~sage.schemes.toric.homset.SchemeHomset_points_toric_field`
397
for example.
398
399
INPUT:
400
401
See :class:`SchemeHomset_generic`.
402
403
EXAMPLES::
404
405
sage: from sage.schemes.generic.homset import SchemeHomset_points
406
sage: SchemeHomset_points(Spec(QQ), AffineSpace(ZZ,2))
407
Set of rational points of Affine Space of dimension 2 over Rational Field
408
"""
409
410
def __init__(self, X, Y, category=None, check=True, base=ZZ):
411
"""
412
Python constructor.
413
414
INPUT:
415
416
See :class:`SchemeHomset_generic`.
417
418
EXAMPLES::
419
420
sage: from sage.schemes.generic.homset import SchemeHomset_points
421
sage: SchemeHomset_points(Spec(QQ), AffineSpace(ZZ,2))
422
Set of rational points of Affine Space of dimension 2 over Rational Field
423
"""
424
if check and not is_Spec(X):
425
raise ValueError('The domain must be an affine scheme.')
426
SchemeHomset_generic.__init__(self, X, Y, category=category, check=check, base=base)
427
428
def _element_constructor_(self, *v, **kwds):
429
"""
430
The element contstructor.
431
432
INPUT:
433
434
- ``v`` -- anything that determines a scheme morphism in the
435
Hom-set.
436
437
OUTPUT:
438
439
The scheme morphism determined by ``v``.
440
441
EXAMPLES::
442
443
sage: A2 = AffineSpace(ZZ,2)
444
sage: F = GF(3)
445
sage: F_points = A2(F); type(F_points)
446
<class 'sage.schemes.affine.affine_homset.SchemeHomset_points_affine_with_category'>
447
sage: F_points([2,5])
448
(2, 2)
449
450
sage: P2 = ProjectiveSpace(GF(3),2)
451
sage: F.<a> = GF(9,'a')
452
sage: F_points = P2(F)
453
sage: type(F_points)
454
<class 'sage.schemes.projective.projective_homset.SchemeHomset_points_projective_field_with_category'>
455
sage: F_points([4,2*a])
456
(1 : 2*a : 1)
457
458
TESTS::
459
460
sage: F_points._element_constructor_([4,2*a])
461
(1 : 2*a : 1)
462
"""
463
if len(v) == 1:
464
v = v[0]
465
return self.codomain()._point(self, v, **kwds)
466
467
def extended_codomain(self):
468
"""
469
Return the codomain with extended base, if necessary.
470
471
OUTPUT:
472
473
The codomain scheme, with its base ring extended to the
474
codomain. That is, the codomain is of the form `Spec(R)` and
475
the base ring of the domain is extended to `R`.
476
477
EXAMPLES::
478
479
sage: P2 = ProjectiveSpace(QQ,2)
480
sage: K.<a> = NumberField(x^2 + x - (3^3-3))
481
sage: K_points = P2(K); K_points
482
Set of rational points of Projective Space of dimension 2
483
over Number Field in a with defining polynomial x^2 + x - 24
484
485
sage: K_points.codomain()
486
Projective Space of dimension 2 over Rational Field
487
488
sage: K_points.extended_codomain()
489
Projective Space of dimension 2 over Number Field in a with
490
defining polynomial x^2 + x - 24
491
"""
492
if '_extended_codomain' in self.__dict__:
493
return self._extended_codomain
494
R = self.domain().coordinate_ring()
495
if R is not self.codomain().base_ring():
496
X = self.codomain().base_extend(R)
497
else:
498
X = self.codomain()
499
self._extended_codomain = X
500
return X
501
502
def _repr_(self):
503
"""
504
Return a string representation of ``self``.
505
506
OUTPUT:
507
508
A string.
509
510
EXAMPLES::
511
512
sage: P2 = ProjectiveSpace(ZZ,2)
513
sage: P2(QQ)._repr_()
514
'Set of rational points of Projective Space of dimension 2 over Rational Field'
515
"""
516
return 'Set of rational points of '+str(self.extended_codomain())
517
518
def value_ring(self):
519
"""
520
Return `R` for a point Hom-set `X(Spec(R))`.
521
522
OUTPUT:
523
524
A commutative ring.
525
526
EXAMPLES::
527
528
sage: P2 = ProjectiveSpace(ZZ,2)
529
sage: P2(QQ).value_ring()
530
Rational Field
531
"""
532
dom = self.domain()
533
if not is_Spec(dom):
534
raise ValueError("value rings are defined for Spec domains only!")
535
return dom.coordinate_ring()
536
537
def cardinality(self):
538
"""
539
Return the number of points.
540
541
OUTPUT:
542
543
An integer or infinity.
544
545
EXAMPLES::
546
547
sage: toric_varieties.P2().point_set().cardinality()
548
+Infinity
549
550
sage: P2 = toric_varieties.P2(base_ring=GF(3))
551
sage: P2.point_set().cardinality()
552
13
553
"""
554
if hasattr(self, 'is_finite') and not self.is_finite():
555
from sage.rings.infinity import Infinity
556
return Infinity
557
return sum(ZZ.one() for point in self)
558
559
__len__ = cardinality
560
561
def list(self):
562
"""
563
Return a tuple containing all points.
564
565
OUTPUT:
566
567
A tuple containing all points of the toric variety.
568
569
EXAMPLE::
570
571
sage: P1 = toric_varieties.P1(base_ring=GF(3))
572
sage: P1.point_set().list()
573
([0 : 1], [1 : 0], [1 : 1], [1 : 2])
574
"""
575
return tuple(self)
576
577