Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/generic/algebraic_scheme.py
8820 views
1
r"""
2
Algebraic schemes
3
4
An algebraic scheme is defined by a set of polynomials in some
5
suitable affine or projective coordinates. Possible ambient spaces are
6
7
* Affine spaces (:class:`AffineSpace
8
<sage.schemes.affine.affine_space.AffineSpace_generic>`),
9
10
* Projective spaces (:class:`ProjectiveSpace
11
<sage.schemes.projective.projective_space.ProjectiveSpace_ring>`), or
12
13
* Toric varieties (:class:`ToricVariety
14
<sage.schemes.toric.variety.ToricVariety_field>`).
15
16
Note that while projective spaces are of course toric varieties themselves,
17
they are implemented differently in Sage due to efficiency considerations.
18
You still can create a projective space as a toric variety if you wish.
19
20
In the following, we call the corresponding subschemes affine
21
algebraic schemes, projective algebraic schemes, or toric algebraic
22
schemes. In the future other ambient spaces, perhaps by means of
23
gluing relations, may be intoduced.
24
25
Generally, polynomials `p_0, p_1, \dots, p_n` define an ideal
26
`I=\left<p_0, p_1, \dots, p_n\right>`. In the projective and toric case, the
27
polynomials (and, therefore, the ideal) must be homogeneous. The
28
associated subscheme `V(I)` of the ambient space is, roughly speaking,
29
the subset of the ambient space on which all polynomials vanish simultaneously.
30
31
.. WARNING::
32
33
You should not construct algebraic scheme objects directly. Instead, use
34
``.subscheme()`` methods of ambient spaces. See below for examples.
35
36
EXAMPLES:
37
38
We first construct the ambient space, here the affine space `\QQ^2`::
39
40
sage: A2 = AffineSpace(2, QQ, 'x, y')
41
sage: A2.coordinate_ring().inject_variables()
42
Defining x, y
43
44
Now we can write polynomial equations in the variables `x` and `y`. For
45
example, one equation cuts out a curve (a one-dimensional subscheme)::
46
47
sage: V = A2.subscheme([x^2+y^2-1]); V
48
Closed subscheme of Affine Space of dimension 2
49
over Rational Field defined by:
50
x^2 + y^2 - 1
51
sage: V.dimension()
52
1
53
54
Here is a more complicated example in a projective space::
55
56
sage: P3 = ProjectiveSpace(3, QQ, 'x')
57
sage: P3.inject_variables()
58
Defining x0, x1, x2, x3
59
sage: Q = matrix([[x0, x1, x2], [x1, x2, x3]]).minors(2); Q
60
[-x1^2 + x0*x2, -x1*x2 + x0*x3, -x2^2 + x1*x3]
61
sage: twisted_cubic = P3.subscheme(Q)
62
sage: twisted_cubic
63
Closed subscheme of Projective Space of dimension 3
64
over Rational Field defined by:
65
-x1^2 + x0*x2,
66
-x1*x2 + x0*x3,
67
-x2^2 + x1*x3
68
sage: twisted_cubic.dimension()
69
1
70
71
Note that there are 3 equations in the 3-dimensional ambient space,
72
yet the subscheme is 1-dimensional. One can show that it is not
73
possible to eliminate any of the equations, that is, the twisted cubic
74
is **not** a complete intersection of two polynomial equations.
75
76
Let us look at one affine patch, for example the one where `x_0=1` ::
77
78
sage: patch = twisted_cubic.affine_patch(0)
79
sage: patch
80
Closed subscheme of Affine Space of dimension 3
81
over Rational Field defined by:
82
-x0^2 + x1,
83
-x0*x1 + x2,
84
-x1^2 + x0*x2
85
sage: patch.embedding_morphism()
86
Scheme morphism:
87
From: Closed subscheme of Affine Space of dimension 3
88
over Rational Field defined by:
89
-x0^2 + x1,
90
-x0*x1 + x2,
91
-x1^2 + x0*x2
92
To: Closed subscheme of Projective Space of dimension 3
93
over Rational Field defined by:
94
-x1^2 + x0*x2,
95
-x1*x2 + x0*x3,
96
-x2^2 + x1*x3
97
Defn: Defined on coordinates by sending (x0, x1, x2) to
98
(1 : x0 : x1 : x2)
99
100
101
AUTHORS:
102
103
- David Kohel (2005): initial version.
104
- William Stein (2005): initial version.
105
- Andrey Novoseltsev (2010-05-17): subschemes of toric varieties.
106
- Volker Braun (2010-12-24): documentation of schemes and
107
refactoring. Added coordinate neighborhoods and is_smooth()
108
"""
109
110
#*****************************************************************************
111
# Copyright (C) 2010 Volker Braun <[email protected]>
112
# Copyright (C) 2005 David Kohel <[email protected]>
113
# Copyright (C) 2010 Andrey Novoseltsev <[email protected]>
114
# Copyright (C) 2005 William Stein <[email protected]>
115
#
116
# Distributed under the terms of the GNU General Public License (GPL)
117
# as published by the Free Software Foundation; either version 2 of
118
# the License, or (at your option) any later version.
119
# http://www.gnu.org/licenses/
120
#*****************************************************************************
121
122
123
#*** A quick overview over the class hierarchy:
124
# class AlgebraicScheme(scheme.Scheme)
125
# class AlgebraicScheme_subscheme
126
# class AlgebraicScheme_subscheme_affine
127
# class AlgebraicScheme_subscheme_projective
128
# class AlgebraicScheme_subscheme_toric
129
# class AlgebraicScheme_subscheme_affine_toric
130
# class AlgebraicScheme_quasi
131
132
133
134
from sage.rings.all import ZZ
135
136
from sage.rings.ideal import is_Ideal
137
from sage.rings.rational_field import is_RationalField
138
from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
139
from sage.rings.finite_rings.constructor import is_FiniteField
140
141
from sage.misc.latex import latex
142
from sage.misc.misc import is_iterator
143
from sage.structure.all import Sequence
144
from sage.calculus.functions import jacobian
145
146
import sage.schemes.projective
147
import sage.schemes.affine
148
import ambient_space
149
import scheme
150
151
152
153
#*******************************************************************
154
def is_AlgebraicScheme(x):
155
"""
156
Test whether ``x`` is an algebraic scheme.
157
158
INPUT:
159
160
- ``x`` -- anything.
161
162
OUTPUT:
163
164
Boolean. Whether ``x`` is an an algebraic scheme, that is, a
165
subscheme of an ambient space over a ring defined by polynomial
166
equations.
167
168
EXAMPLES::
169
170
sage: A2 = AffineSpace(2, QQ, 'x, y')
171
sage: A2.coordinate_ring().inject_variables()
172
Defining x, y
173
sage: V = A2.subscheme([x^2+y^2]); V
174
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
175
x^2 + y^2
176
sage: from sage.schemes.generic.algebraic_scheme import is_AlgebraicScheme
177
sage: is_AlgebraicScheme(V)
178
True
179
180
Affine space is itself not an algebraic scheme, though the closed
181
subscheme defined by no equations is::
182
183
sage: from sage.schemes.generic.algebraic_scheme import is_AlgebraicScheme
184
sage: is_AlgebraicScheme(AffineSpace(10, QQ))
185
False
186
sage: V = AffineSpace(10, QQ).subscheme([]); V
187
Closed subscheme of Affine Space of dimension 10 over Rational Field defined by:
188
(no polynomials)
189
sage: is_AlgebraicScheme(V)
190
True
191
192
We create a more complicated closed subscheme::
193
194
sage: A, x = AffineSpace(10, QQ).objgens()
195
sage: X = A.subscheme([sum(x)]); X
196
Closed subscheme of Affine Space of dimension 10 over Rational Field defined by:
197
x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
198
sage: is_AlgebraicScheme(X)
199
True
200
201
::
202
203
sage: is_AlgebraicScheme(QQ)
204
False
205
sage: S = Spec(QQ)
206
sage: is_AlgebraicScheme(S)
207
False
208
"""
209
return isinstance(x, AlgebraicScheme)
210
211
212
213
#*******************************************************************
214
class AlgebraicScheme(scheme.Scheme):
215
"""
216
An algebraic scheme presented as a subscheme in an ambient space.
217
218
This is the base class for all algebraic schemes, that is, schemes
219
defined by equations in affine, projective, or toric ambient
220
spaces.
221
"""
222
223
def __init__(self, A):
224
"""
225
TESTS::
226
227
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme
228
sage: P = ProjectiveSpace(3, ZZ)
229
sage: P.category()
230
Category of schemes over Integer Ring
231
sage: S = AlgebraicScheme(P); S
232
Subscheme of Projective Space of dimension 3 over Integer Ring
233
sage: S.category()
234
Category of schemes over Integer Ring
235
"""
236
if not ambient_space.is_AmbientSpace(A):
237
raise TypeError, "A (=%s) must be an ambient space"
238
self.__A = A
239
self.__divisor_group = {}
240
scheme.Scheme.__init__(self, A.base_scheme())
241
242
def _latex_(self):
243
"""
244
Return a LaTeX representation of this algebraic scheme.
245
246
TESTS::
247
248
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme
249
sage: P = ProjectiveSpace(3, ZZ)
250
sage: S = AlgebraicScheme(P); S
251
Subscheme of Projective Space of dimension 3 over Integer Ring
252
sage: S._latex_()
253
'\text{Subscheme of } {\\mathbf P}_{\\Bold{Z}}^3'
254
"""
255
return "\text{Subscheme of } %s" % latex(self.__A)
256
257
def is_projective(self):
258
"""
259
Return True if self is presented as a subscheme of an ambient
260
projective space.
261
262
OUTPUT:
263
264
Boolean.
265
266
EXAMPLES::
267
268
sage: PP.<x,y,z,w> = ProjectiveSpace(3,QQ)
269
sage: f = x^3 + y^3 + z^3 + w^3
270
sage: R = f.parent()
271
sage: I = [f] + [f.derivative(zz) for zz in PP.gens()]
272
sage: V = PP.subscheme(I)
273
sage: V.is_projective()
274
True
275
sage: AA.<x,y,z,w> = AffineSpace(4,QQ)
276
sage: V = AA.subscheme(I)
277
sage: V.is_projective()
278
False
279
280
Note that toric varieties are implemented differently than
281
projective spaces. This is why this method returns ``False``
282
for toric varieties::
283
284
sage: PP.<x,y,z,w> = toric_varieties.P(3)
285
sage: V = PP.subscheme(x^3 + y^3 + z^3 + w^3)
286
sage: V.is_projective()
287
False
288
"""
289
return self.ambient_space().is_projective()
290
291
def coordinate_ring(self):
292
"""
293
Return the coordinate ring of this algebraic scheme. The
294
result is cached.
295
296
OUTPUT:
297
298
The coordinate ring. Usually a polynomial ring, or a quotient
299
thereof.
300
301
EXAMPLES::
302
303
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
304
sage: S = P.subscheme([x-y, x-z])
305
sage: S.coordinate_ring()
306
Quotient of Multivariate Polynomial Ring in x, y, z over Integer Ring by the ideal (x - y, x - z)
307
"""
308
try:
309
return self._coordinate_ring
310
except AttributeError:
311
R = self.__A.coordinate_ring()
312
I = self.defining_ideal()
313
Q = R.quotient(I)
314
self._coordinate_ring = Q
315
return Q
316
317
def ambient_space(self):
318
"""
319
Return the ambient space of this algebraic scheme.
320
321
EXAMPLES::
322
323
sage: A.<x, y> = AffineSpace(2, GF(5))
324
sage: S = A.subscheme([])
325
sage: S.ambient_space()
326
Affine Space of dimension 2 over Finite Field of size 5
327
328
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
329
sage: S = P.subscheme([x-y, x-z])
330
sage: S.ambient_space() is P
331
True
332
"""
333
return self.__A
334
335
def embedding_morphism(self):
336
r"""
337
Return the default embedding morphism of ``self``.
338
339
If the scheme `Y` was constructed as a neighbourhood of a
340
point `p \in X`, then :meth:`embedding_morphism` returns a
341
local isomorphism `f:Y\to X` around the preimage point
342
`f^{-1}(p)`. The latter is returned by
343
:meth:`embedding_center`.
344
345
If the algebraic scheme `Y` was not constructed as a
346
neighbourhood of a point, then the embedding in its
347
:meth:`ambient_space` is returned.
348
349
OUTPUT:
350
351
A scheme morphism whose
352
:meth:`~morphism.SchemeMorphism.domain` is ``self``.
353
354
* By default, it is the tautological embedding into its own
355
ambient space :meth:`ambient_space`.
356
357
* If the algebraic scheme (which itself is a subscheme of an
358
auxiliary :meth:`ambient_space`) was constructed as a patch
359
or neighborhood of a point then the embedding is the
360
embedding into the original scheme.
361
362
* A ``NotImplementedError`` is raised if the construction of
363
the embedding morphism is not implemented yet.
364
365
EXAMPLES::
366
367
sage: A2.<x,y> = AffineSpace(QQ,2)
368
sage: C = A2.subscheme(x^2+y^2-1)
369
sage: C.embedding_morphism()
370
Scheme morphism:
371
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
372
x^2 + y^2 - 1
373
To: Affine Space of dimension 2 over Rational Field
374
Defn: Defined on coordinates by sending (x, y) to
375
(x, y)
376
sage: P1xP1.<x,y,u,v> = toric_varieties.P1xP1()
377
sage: P1 = P1xP1.subscheme(x-y)
378
sage: P1.embedding_morphism()
379
Scheme morphism:
380
From: Closed subscheme of 2-d CPR-Fano toric variety covered
381
by 4 affine patches defined by:
382
x - y
383
To: 2-d CPR-Fano toric variety covered by 4 affine patches
384
Defn: Defined on coordinates by sending [x : y : u : v] to
385
[y : y : u : v]
386
387
So far, the embedding was just in the own ambient space. Now a
388
bit more interesting examples::
389
390
sage: P2.<x,y,z> = ProjectiveSpace(QQ,2)
391
sage: X = P2.subscheme((x^2-y^2)*z)
392
sage: p = (1,1,0)
393
sage: nbhd = X.neighborhood(p)
394
sage: nbhd
395
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
396
-x0^2*x1 - 2*x0*x1
397
398
Note that `p=(1,1,0)` is a singular point of `X`. So the
399
neighborhood of `p` is not just affine space. The
400
:meth:neighborhood` method returns a presentation of
401
the neighborhood as a subscheme of an auxiliary 2-dimensional
402
affine space::
403
404
sage: nbhd.ambient_space()
405
Affine Space of dimension 2 over Rational Field
406
407
But its :meth:`embedding_morphism` is not into this auxiliary
408
affine space, but the original subscheme `X`::
409
410
sage: nbhd.embedding_morphism()
411
Scheme morphism:
412
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
413
-x0^2*x1 - 2*x0*x1
414
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
415
x^2*z - y^2*z
416
Defn: Defined on coordinates by sending (x0, x1) to
417
(1 : x0 + 1 : x1)
418
419
A couple more examples::
420
421
sage: patch1 = P1xP1.affine_patch(1)
422
sage: patch1
423
2-d affine toric variety
424
sage: patch1.embedding_morphism()
425
Scheme morphism:
426
From: 2-d affine toric variety
427
To: 2-d CPR-Fano toric variety covered by 4 affine patches
428
Defn: Defined on coordinates by sending [y : u] to
429
[1 : y : u : 1]
430
sage: subpatch = P1.affine_patch(1)
431
sage: subpatch
432
Closed subscheme of 2-d affine toric variety defined by:
433
-y + 1
434
sage: subpatch.embedding_morphism()
435
Scheme morphism:
436
From: Closed subscheme of 2-d affine toric variety defined by:
437
-y + 1
438
To: Closed subscheme of 2-d CPR-Fano toric variety covered
439
by 4 affine patches defined by:
440
x - y
441
Defn: Defined on coordinates by sending [y : u] to
442
[1 : y : u : 1]
443
"""
444
if '_embedding_morphism' in self.__dict__:
445
hom = self._embedding_morphism
446
if isinstance(hom, tuple):
447
raise(hom[0], hom[1])
448
return hom
449
ambient = self.ambient_space()
450
return self.hom(ambient.coordinate_ring().gens(), ambient)
451
452
def embedding_center(self):
453
r"""
454
Return the distinguished point, if there is any.
455
456
If the scheme `Y` was constructed as a neighbourhood of a
457
point `p \in X`, then :meth:`embedding_morphism` returns a
458
local isomorphism `f:Y\to X` around the preimage point
459
`f^{-1}(p)`. The latter is returned by
460
:meth:`embedding_center`.
461
462
OUTPUT:
463
464
A point of ``self``. Raises ``AttributeError`` if there is no
465
distinguished point, depending on how ``self`` was
466
constructed.
467
468
EXAMPLES::
469
470
sage: P3.<w,x,y,z> = ProjectiveSpace(QQ,3)
471
sage: X = P3.subscheme( (w^2-x^2)*(y^2-z^2) )
472
sage: p = [1,-1,3,4]
473
sage: nbhd = X.neighborhood(p); nbhd
474
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
475
x0^2*x2^2 - x1^2*x2^2 + 6*x0^2*x2 - 6*x1^2*x2 + 2*x0*x2^2 +
476
2*x1*x2^2 - 7*x0^2 + 7*x1^2 + 12*x0*x2 + 12*x1*x2 - 14*x0 - 14*x1
477
sage: nbhd.embedding_center()
478
(0, 0, 0)
479
sage: nbhd.embedding_morphism()(nbhd.embedding_center())
480
(1/4 : -1/4 : 3/4 : 1)
481
sage: nbhd.embedding_morphism()
482
Scheme morphism:
483
From: Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
484
x0^2*x2^2 - x1^2*x2^2 + 6*x0^2*x2 - 6*x1^2*x2 + 2*x0*x2^2 +
485
2*x1*x2^2 - 7*x0^2 + 7*x1^2 + 12*x0*x2 + 12*x1*x2 - 14*x0 - 14*x1
486
To: Closed subscheme of Projective Space of dimension 3 over Rational Field defined by:
487
w^2*y^2 - x^2*y^2 - w^2*z^2 + x^2*z^2
488
Defn: Defined on coordinates by sending (x0, x1, x2) to
489
(x0 + 1 : x1 - 1 : x2 + 3 : 4)
490
"""
491
if '_embedding_center' in self.__dict__:
492
return self._embedding_center
493
raise AttributeError, 'This algebraic scheme does not have a designated point.'
494
495
def ngens(self):
496
"""
497
Return the number of generators of the ambient space of this
498
algebraic scheme.
499
500
EXAMPLES::
501
502
sage: A.<x, y> = AffineSpace(2, GF(5))
503
sage: S = A.subscheme([])
504
sage: S.ngens()
505
2
506
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
507
sage: S = P.subscheme([x-y, x-z])
508
sage: P.ngens()
509
3
510
"""
511
return self.__A.ngens()
512
513
def _repr_(self):
514
"""
515
Return a string representation of this algebraic scheme.
516
517
TESTS::
518
519
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme
520
sage: P = ProjectiveSpace(3, ZZ)
521
sage: S = AlgebraicScheme(P); S
522
Subscheme of Projective Space of dimension 3 over Integer Ring
523
sage: S._repr_()
524
'Subscheme of Projective Space of dimension 3 over Integer Ring'
525
"""
526
return "Subscheme of %s"%self.__A
527
528
def _homset(self, *args, **kwds):
529
"""
530
Construct the Hom-set
531
532
INPUT:
533
534
Same as :class:`sage.schemes.generic.homset.SchemeHomset_generic`.
535
536
OUTPUT:
537
538
The Hom-set of the ambient space.
539
540
EXAMPLES::
541
542
sage: P1.<x,y> = toric_varieties.P1()
543
sage: type(P1.Hom(P1))
544
<class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'>
545
sage: X = P1.subscheme(x-y)
546
sage: type(X.Hom(X))
547
<class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'>
548
549
::
550
551
sage: P1xP1 = toric_varieties.P1xP1()
552
sage: P1 = toric_varieties.P1()
553
sage: P1xP1._homset(P1xP1,P1)
554
Set of morphisms
555
From: 2-d CPR-Fano toric variety covered by 4 affine patches
556
To: 1-d CPR-Fano toric variety covered by 2 affine patches
557
"""
558
return self.__A._homset(*args, **kwds)
559
560
def _point_homset(self, *args, **kwds):
561
"""
562
Construct a point Hom-set. For internal use only.
563
564
TESTS::
565
566
sage: P2.<x,y,z> = ProjectiveSpace(2, ZZ)
567
sage: P2._point_homset(Spec(ZZ), P2)
568
Set of rational points of Projective Space of dimension 2 over Integer Ring
569
"""
570
return self.__A._point_homset(*args, **kwds)
571
572
def _point(self, *args, **kwds):
573
r"""
574
Construct a point of ``self``. For internal use only.
575
576
TESTS::
577
578
sage: P2.<x,y,z> = ProjectiveSpace(2, QQ)
579
sage: point_homset = P2._point_homset(Spec(QQ), P2)
580
sage: P2._point(point_homset, [1,2,1])
581
(1 : 2 : 1)
582
"""
583
return self.__A._point(*args, **kwds)
584
585
586
587
#*******************************************************************
588
class AlgebraicScheme_quasi(AlgebraicScheme):
589
"""
590
The quasi-affine or quasi-projective scheme `X - Y`, where `X` and `Y`
591
are both closed subschemes of a common ambient affine or projective
592
space.
593
594
.. WARNING::
595
596
You should not create objects of this class directly. The
597
preferred method to construct such subschemes is to use
598
:meth:`complement` method of algebraic schemes.
599
600
OUTPUT:
601
602
An instance of :class:`AlgebraicScheme_quasi`.
603
604
EXAMPLES::
605
606
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
607
sage: S = P.subscheme([])
608
sage: T = P.subscheme([x-y])
609
sage: T.complement(S)
610
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over
611
Integer Ring, where X is defined by:
612
(no polynomials)
613
and Y is defined by:
614
x - y
615
"""
616
617
def __init__(self, X, Y):
618
"""
619
The constructor.
620
621
INPUT:
622
623
- ``X``, ``Y`` -- two subschemes of the same ambient space.
624
625
TESTS::
626
627
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
628
sage: S = P.subscheme([])
629
sage: T = P.subscheme([x-y])
630
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
631
sage: AlgebraicScheme_quasi(S, T)
632
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:
633
(no polynomials)
634
and Y is defined by:
635
x - y
636
"""
637
self.__X = X
638
self.__Y = Y
639
if not isinstance(X, AlgebraicScheme_subscheme):
640
raise TypeError, "X must be a closed subscheme of an ambient space."
641
if not isinstance(Y, AlgebraicScheme_subscheme):
642
raise TypeError, "Y must be a closed subscheme of an ambient space."
643
if X.ambient_space() != Y.ambient_space():
644
raise ValueError, "X and Y must be embedded in the same ambient space."
645
# _latex_ and _repr_ assume all of the above conditions and should be
646
# probably changed if they are relaxed!
647
A = X.ambient_space()
648
self._base_ring = A.base_ring()
649
AlgebraicScheme.__init__(self, A)
650
651
def _latex_(self):
652
"""
653
Return a LaTeX representation of this algebraic scheme.
654
655
EXAMPLES::
656
657
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
658
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
659
sage: S = P.subscheme([])
660
sage: T = P.subscheme([x-y])
661
sage: U = AlgebraicScheme_quasi(S, T); U
662
Quasi-projective subscheme X - Y of Projective Space of dimension 2
663
over Integer Ring, where X is defined by:
664
(no polynomials)
665
and Y is defined by:
666
x - y
667
sage: U._latex_()
668
'\\text{Quasi-projective subscheme }
669
(X\\setminus Y)\\subset {\\mathbf P}_{\\Bold{Z}}^2,\\text{ where }
670
X \\text{ is defined by }\\text{no polynomials},\\text{ and }
671
Y \\text{ is defined by } x - y.'
672
"""
673
if sage.schemes.affine.affine_space.is_AffineSpace(self.ambient_space()):
674
t = "affine"
675
else:
676
t = "projective"
677
X = ', '.join(latex(f) for f in self.__X.defining_polynomials())
678
if not X:
679
X = r"\text{no polynomials}"
680
Y = ', '.join(latex(f) for f in self.__Y.defining_polynomials())
681
if not Y:
682
Y = r"\text{no polynomials}"
683
return (r"\text{Quasi-%s subscheme } (X\setminus Y)\subset %s,"
684
r"\text{ where } X \text{ is defined by }%s,"
685
r"\text{ and } Y \text{ is defined by } %s."
686
% (t, latex(self.ambient_space()), X, Y))
687
688
def _repr_(self):
689
"""
690
Return a string representation of this algebraic scheme.
691
692
EXAMPLES::
693
694
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
695
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
696
sage: S = P.subscheme([])
697
sage: T = P.subscheme([x-y])
698
sage: U = AlgebraicScheme_quasi(S, T); U
699
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:
700
(no polynomials)
701
and Y is defined by:
702
x - y
703
sage: U._repr_()
704
'Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:\n (no polynomials)\nand Y is defined by:\n x - y'
705
"""
706
if sage.schemes.affine.affine_space.is_AffineSpace(self.ambient_space()):
707
t = "affine"
708
else:
709
t = "projective"
710
return ("Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\n"
711
"and Y is defined by:\n%s"
712
% (t, self.ambient_space(), str(self.__X).split("\n", 1)[1],
713
str(self.__Y).split("\n", 1)[1]))
714
715
def X(self):
716
"""
717
Return the scheme `X` such that self is represented as `X - Y`.
718
719
EXAMPLES::
720
721
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
722
sage: S = P.subscheme([])
723
sage: T = P.subscheme([x-y])
724
sage: U = T.complement(S)
725
sage: U.X() is S
726
True
727
"""
728
return self.__X
729
730
def Y(self):
731
"""
732
Return the scheme `Y` such that self is represented as `X - Y`.
733
734
EXAMPLES::
735
736
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
737
sage: S = P.subscheme([])
738
sage: T = P.subscheme([x-y])
739
sage: U = T.complement(S)
740
sage: U.Y() is T
741
True
742
"""
743
return self.__Y
744
745
def _check_satisfies_equations(self, v):
746
"""
747
Verify that the coordinates of v define a point on this scheme, or
748
raise a TypeError.
749
750
EXAMPLES::
751
752
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
753
sage: S = P.subscheme([])
754
sage: T = P.subscheme([x-y])
755
sage: U = T.complement(S)
756
sage: U._check_satisfies_equations([1, 2, 0])
757
True
758
sage: U._check_satisfies_equations([1, 1, 0])
759
Traceback (most recent call last):
760
...
761
TypeError: Coordinates [1, 1, 0] do not define a point on
762
Quasi-projective subscheme X - Y of Projective Space of dimension 2
763
over Integer Ring, where X is defined by:
764
(no polynomials)
765
and Y is defined by:
766
x - y
767
768
sage: U._check_satisfies_equations([1, 4])
769
Traceback (most recent call last):
770
...
771
TypeError: number of arguments does not match number of variables in parent
772
773
sage: A.<x, y> = AffineSpace(2, GF(7))
774
sage: S = A.subscheme([x^2-y])
775
sage: T = A.subscheme([x-y])
776
sage: U = T.complement(S)
777
sage: U._check_satisfies_equations([2, 4])
778
True
779
sage: U.point([2,4])
780
(2, 4)
781
sage: U._check_satisfies_equations(_)
782
True
783
sage: U._check_satisfies_equations([1, 1])
784
Traceback (most recent call last):
785
...
786
TypeError: Coordinates [1, 1] do not define a point on Quasi-affine
787
subscheme X - Y of Affine Space of dimension 2 over Finite
788
Field of size 7, where X is defined by:
789
x^2 - y
790
and Y is defined by:
791
x - y
792
sage: U._check_satisfies_equations([1, 0])
793
Traceback (most recent call last):
794
...
795
TypeError: Coordinates [1, 0] do not define a point on Quasi-affine
796
subscheme X - Y of Affine Space of dimension 2 over Finite
797
Field of size 7, where X is defined by:
798
x^2 - y
799
and Y is defined by:
800
x - y
801
802
TESTS:
803
804
The bug reported at #12211 has been fixed::
805
806
sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ)
807
sage: S = P.subscheme([x])
808
sage: T = P.subscheme([y, z])
809
sage: U = T.complement(S)
810
sage: U._check_satisfies_equations([0, 0, 1, 1])
811
True
812
"""
813
coords = list(v)
814
for f in self.__X.defining_polynomials():
815
if f(coords) != 0:
816
raise TypeError, "Coordinates %s do not define a point on %s"%(v,self)
817
for f in self.__Y.defining_polynomials():
818
if f(coords) != 0:
819
return True
820
raise TypeError, "Coordinates %s do not define a point on %s"%(v,self)
821
822
def rational_points(self, F=None, bound=0):
823
"""
824
Return the set of rational points on this algebraic scheme
825
over the field `F`.
826
827
EXAMPLES::
828
829
sage: A.<x, y> = AffineSpace(2, GF(7))
830
sage: S = A.subscheme([x^2-y])
831
sage: T = A.subscheme([x-y])
832
sage: U = T.complement(S)
833
sage: U.rational_points()
834
[(2, 4), (3, 2), (4, 2), (5, 4), (6, 1)]
835
sage: U.rational_points(GF(7^2, 'b'))
836
[(2, 4), (3, 2), (4, 2), (5, 4), (6, 1), (b, b + 4), (b + 1, 3*b + 5), (b + 2, 5*b + 1),
837
(b + 3, 6), (b + 4, 2*b + 6), (b + 5, 4*b + 1), (b + 6, 6*b + 5), (2*b, 4*b + 2),
838
(2*b + 1, b + 3), (2*b + 2, 5*b + 6), (2*b + 3, 2*b + 4), (2*b + 4, 6*b + 4),
839
(2*b + 5, 3*b + 6), (2*b + 6, 3), (3*b, 2*b + 1), (3*b + 1, b + 2), (3*b + 2, 5),
840
(3*b + 3, 6*b + 3), (3*b + 4, 5*b + 3), (3*b + 5, 4*b + 5), (3*b + 6, 3*b + 2),
841
(4*b, 2*b + 1), (4*b + 1, 3*b + 2), (4*b + 2, 4*b + 5), (4*b + 3, 5*b + 3),
842
(4*b + 4, 6*b + 3), (4*b + 5, 5), (4*b + 6, b + 2), (5*b, 4*b + 2), (5*b + 1, 3),
843
(5*b + 2, 3*b + 6), (5*b + 3, 6*b + 4), (5*b + 4, 2*b + 4), (5*b + 5, 5*b + 6),
844
(5*b + 6, b + 3), (6*b, b + 4), (6*b + 1, 6*b + 5), (6*b + 2, 4*b + 1), (6*b + 3, 2*b + 6),
845
(6*b + 4, 6), (6*b + 5, 5*b + 1), (6*b + 6, 3*b + 5)]
846
"""
847
if F is None:
848
F = self.base_ring()
849
850
if bound == 0:
851
if is_RationalField(F):
852
raise TypeError, "A positive bound (= %s) must be specified."%bound
853
if not is_FiniteField(F):
854
raise TypeError, "Argument F (= %s) must be a finite field."%F
855
pts = []
856
for P in self.ambient_space().rational_points(F):
857
try:
858
if self._check_satisfies_equations(list(P)):
859
pts.append(P)
860
except TypeError:
861
pass
862
pts.sort()
863
return pts
864
865
866
867
#*******************************************************************
868
class AlgebraicScheme_subscheme(AlgebraicScheme):
869
"""
870
An algebraic scheme presented as a closed subscheme is defined by
871
explicit polynomial equations. This is as opposed to a general
872
scheme, which could, e.g., be the Neron model of some object, and
873
for which we do not want to give explicit equations.
874
875
INPUT:
876
877
- ``A`` - ambient space (e.g. affine or projective `n`-space)
878
879
- ``polynomials`` - single polynomial, ideal or iterable of defining
880
polynomials; in any case polynomials must belong to the coordinate
881
ring of the ambient space and define valid polynomial functions (e.g.
882
they should be homogeneous in the case of a projective space)
883
884
OUTPUT:
885
886
- algebraic scheme
887
888
EXAMPLES::
889
890
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
891
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
892
sage: P.subscheme([x^2-y*z])
893
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
894
x^2 - y*z
895
sage: AlgebraicScheme_subscheme(P, [x^2-y*z])
896
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
897
x^2 - y*z
898
"""
899
900
def __init__(self, A, polynomials):
901
"""
902
See ``AlgebraicScheme_subscheme`` for documentation.
903
904
TESTS::
905
906
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
907
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
908
sage: P.subscheme([x^2-y*z])
909
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
910
x^2 - y*z
911
sage: AlgebraicScheme_subscheme(P, [x^2-y*z])
912
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
913
x^2 - y*z
914
"""
915
from sage.rings.polynomial.multi_polynomial_sequence import is_PolynomialSequence
916
917
AlgebraicScheme.__init__(self, A)
918
self._base_ring = A.base_ring()
919
R = A.coordinate_ring()
920
if is_Ideal(polynomials):
921
I = polynomials
922
polynomials = I.gens()
923
if I.ring() is R: # Otherwise we will recompute I later after
924
self.__I = I # converting generators to the correct ring
925
if isinstance(polynomials, tuple) or is_PolynomialSequence(polynomials) or is_iterator(polynomials):
926
polynomials = list(polynomials)
927
elif not isinstance(polynomials, list):
928
# Looks like we got a single polynomial
929
polynomials = [polynomials]
930
for n, f in enumerate(polynomials):
931
try:
932
polynomials[n] = R(f)
933
except TypeError:
934
raise TypeError("%s cannot be converted to a polynomial in "
935
"the coordinate ring of this %s!" % (f, A))
936
polynomials = tuple(polynomials)
937
self.__polys = A._validate(polynomials)
938
939
def _check_satisfies_equations(self, v):
940
"""
941
Verify that the coordinates of v define a point on this scheme, or
942
raise a TypeError.
943
944
EXAMPLES::
945
946
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
947
sage: S = P.subscheme([x^2-y*z])
948
sage: S._check_satisfies_equations([1, 1, 1])
949
True
950
sage: S._check_satisfies_equations([1, 0, 1])
951
Traceback (most recent call last):
952
...
953
TypeError: Coordinates [1, 0, 1] do not define a point on Closed subscheme
954
of Projective Space of dimension 2 over Rational Field defined by:
955
x^2 - y*z
956
sage: S._check_satisfies_equations([0, 0, 0])
957
Traceback (most recent call last):
958
...
959
TypeError: Coordinates [0, 0, 0] do not define a point on Closed subscheme
960
of Projective Space of dimension 2 over Rational Field defined by:
961
x^2 - y*z
962
"""
963
coords = list(v)
964
for f in self.defining_polynomials():
965
if f(coords) != 0: # it must be "!=0" instead of "if f(v)", e.g.,
966
# because of p-adic base rings.
967
raise TypeError, "Coordinates %s do not define a point on %s"%(coords,self)
968
try:
969
return self.ambient_space()._check_satisfies_equations(coords)
970
except TypeError:
971
raise TypeError, "Coordinates %s do not define a point on %s"%(coords,self)
972
973
def base_extend(self, R):
974
"""
975
Return the base change to the ring `R` of this scheme.
976
977
EXAMPLES::
978
979
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
980
sage: S = P.subscheme([x^2-y*z])
981
sage: S.base_extend(GF(11^2, 'b'))
982
Closed subscheme of Projective Space of dimension 2 over Finite Field in b of size 11^2 defined by:
983
x^2 - y*z
984
sage: S.base_extend(ZZ)
985
Traceback (most recent call last):
986
...
987
ValueError: no natural map from the base ring (=Finite Field of size 11) to R (=Integer Ring)!
988
"""
989
A = self.ambient_space().base_extend(R)
990
return A.subscheme(self.__polys)
991
992
def __cmp__(self, other):
993
"""
994
EXAMPLES::
995
996
sage: A.<x, y, z> = AffineSpace(3, QQ)
997
sage: X = A.subscheme([x*y, z])
998
sage: X == A.subscheme([z, x*y])
999
True
1000
sage: X == A.subscheme([x*y, z^2])
1001
False
1002
sage: B.<u, v, t> = AffineSpace(3, QQ)
1003
sage: X == B.subscheme([u*v, t])
1004
False
1005
"""
1006
if not isinstance(other, AlgebraicScheme_subscheme):
1007
return -1
1008
A = self.ambient_space()
1009
if other.ambient_space() != A:
1010
return -1
1011
return cmp(self.defining_ideal(), other.defining_ideal())
1012
1013
def _latex_(self):
1014
"""
1015
Return a LaTeX representation of this scheme.
1016
1017
EXAMPLES::
1018
1019
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
1020
sage: S = P.subscheme([x^2-y*z])
1021
sage: S
1022
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1023
x^2 - y*z
1024
sage: S._latex_()
1025
'\\text{Closed subscheme of } {\\mathbf P}_{\\Bold{F}_{11}}^2 \\text{ defined by } x^{2} - y z'
1026
sage: S = P.subscheme([x^2-y*z, x^5])
1027
sage: S
1028
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1029
x^2 - y*z,
1030
x^5
1031
sage: S._latex_()
1032
'\\text{Closed subscheme of } {\\mathbf P}_{\\Bold{F}_{11}}^2 \\text{ defined by } x^{2} - y z, x^{5}'
1033
"""
1034
polynomials = ', '.join(latex(f) for f in self.defining_polynomials())
1035
if not polynomials:
1036
polynomials = r"\text{no polynomials}"
1037
return (r"\text{Closed subscheme of } %s \text{ defined by } %s"
1038
% (latex(self.ambient_space()), polynomials))
1039
1040
def _repr_(self):
1041
"""
1042
Return a string representation of this scheme.
1043
1044
EXAMPLES::
1045
1046
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
1047
sage: S = P.subscheme([x^2-y*z])
1048
sage: S
1049
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1050
x^2 - y*z
1051
sage: S._repr_()
1052
'Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:\n x^2 - y*z'
1053
sage: S = P.subscheme([x^2-y*z, x^5])
1054
sage: S
1055
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1056
x^2 - y*z,
1057
x^5
1058
sage: S._repr_()
1059
'Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:\n x^2 - y*z,\n x^5'
1060
"""
1061
polynomials = ',\n '.join(str(f) for f in self.defining_polynomials())
1062
if not polynomials:
1063
polynomials = '(no polynomials)'
1064
return ("Closed subscheme of %s defined by:\n %s"
1065
% (self.ambient_space(), polynomials))
1066
1067
def defining_polynomials(self):
1068
"""
1069
Return the polynomials that define this scheme as a subscheme
1070
of its ambient space.
1071
1072
OUTPUT:
1073
1074
A tuple of polynomials in the coordinate ring of the ambient
1075
space.
1076
1077
EXAMPLES::
1078
1079
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
1080
sage: S = P.subscheme([x^2-y*z, x^3+z^3])
1081
sage: S.defining_polynomials()
1082
(x^2 - y*z, x^3 + z^3)
1083
"""
1084
return self.__polys
1085
1086
def defining_ideal(self):
1087
"""
1088
Return the ideal that defines this scheme as a subscheme
1089
of its ambient space.
1090
1091
OUTPUT:
1092
1093
An ideal in the coordinate ring of the ambient space.
1094
1095
EXAMPLES::
1096
1097
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
1098
sage: S = P.subscheme([x^2-y*z, x^3+z^3])
1099
sage: S.defining_ideal()
1100
Ideal (x^2 - y*z, x^3 + z^3) of Multivariate Polynomial Ring in x, y, z over Integer Ring
1101
"""
1102
try:
1103
return self.__I
1104
except AttributeError:
1105
R = self.ambient_space().coordinate_ring()
1106
self.__I = R.ideal(self.defining_polynomials())
1107
return self.__I
1108
1109
# Note: dimension must be implemented by the derived classes
1110
def codimension(self):
1111
r"""
1112
Return the codimension of the algebraic subscheme.
1113
1114
OUTPUT:
1115
1116
Integer.
1117
1118
EXAMPLES::
1119
1120
sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ)
1121
sage: V = PP.subscheme(x*y)
1122
sage: V.codimension()
1123
1
1124
sage: V.dimension()
1125
3
1126
"""
1127
return self.ambient_space().dimension() - self.dimension()
1128
1129
def irreducible_components(self):
1130
r"""
1131
Return the irreducible components of this algebraic scheme, as
1132
subschemes of the same ambient space.
1133
1134
OUTPUT: an immutable sequence of irreducible subschemes of the
1135
ambient space of this scheme
1136
1137
The components are cached.
1138
1139
EXAMPLES:
1140
1141
We define what is clearly a union of four hypersurfaces in
1142
`\P^4_{\QQ}` then find the irreducible components::
1143
1144
sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ)
1145
sage: V = PP.subscheme( (x^2 - y^2 - z^2)*(w^5 - 2*v^2*z^3)* w * (v^3 - x^2*z) )
1146
sage: V.irreducible_components()
1147
[
1148
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1149
w,
1150
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1151
x^2 - y^2 - z^2,
1152
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1153
x^2*z - v^3,
1154
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1155
w^5 - 2*z^3*v^2
1156
]
1157
1158
We verify that the irrelevant ideal isn't accidently returned
1159
(see trac 6920)::
1160
1161
sage: PP.<x,y,z,w> = ProjectiveSpace(3,QQ)
1162
sage: f = x^3 + y^3 + z^3 + w^3
1163
sage: R = f.parent()
1164
sage: I = [f] + [f.derivative(zz) for zz in PP.gens()]
1165
sage: V = PP.subscheme(I)
1166
sage: V.irreducible_components()
1167
[
1168
<BLANKLINE>
1169
]
1170
1171
The same polynomial as above defines a scheme with a
1172
nontrivial irreducible component in affine space (instead of
1173
the empty scheme as above)::
1174
1175
sage: AA.<x,y,z,w> = AffineSpace(4,QQ)
1176
sage: V = AA.subscheme(I)
1177
sage: V.irreducible_components()
1178
[
1179
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
1180
w,
1181
z,
1182
y,
1183
x
1184
]
1185
"""
1186
try:
1187
return self.__irreducible_components
1188
except AttributeError:
1189
pass
1190
I = self.defining_ideal()
1191
P = I.associated_primes()
1192
if self.is_projective():
1193
# In the projective case, we must exclude the prime ideals
1194
# that contain the irrelevant ideal, which is the ideal
1195
# generated by the variables, which are the gens of the
1196
# base ring.
1197
G = I.ring().gens()
1198
# We make a list of ideals with the property that "any"
1199
# of the elements of G are not in the ideal.
1200
P = [J for J in P if any(g not in J for g in G)]
1201
1202
A = self.ambient_space()
1203
C = Sequence([A.subscheme(X) for X in P], check=False, cr=True)
1204
C.sort()
1205
C.set_immutable()
1206
self.__irreducible_components = C
1207
return C
1208
1209
def Jacobian_matrix(self):
1210
r"""
1211
Return the matrix `\frac{\partial f_i}{\partial x_j}` of
1212
(formal) partial derivatives.
1213
1214
OUTPUT:
1215
1216
A matrix of polynomials.
1217
1218
EXAMPLES::
1219
1220
sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ)
1221
sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2))
1222
sage: twisted_cubic.Jacobian_matrix()
1223
[ y -2*x w 0]
1224
[ z -y -x w]
1225
[ 0 z -2*y x]
1226
"""
1227
R = self.ambient_space().coordinate_ring()
1228
return jacobian(self.defining_polynomials(), R.gens())
1229
1230
def Jacobian(self):
1231
r"""
1232
Return the Jacobian ideal.
1233
1234
This is the ideal generated by
1235
1236
* the `d\times d` minors of the Jacobian matrix, where `d` is
1237
the :meth:`codimension` of the algebraic scheme, and
1238
1239
* the defining polynomials of the algebraic scheme. Note that
1240
some authors do not include these in the definition of the
1241
Jacobian ideal. An example of a reference that does include
1242
the defining equations is [LazarsfeldJacobian].
1243
1244
OUTPUT:
1245
1246
An ideal in the coordinate ring of the ambient space.
1247
1248
REFERENCES:
1249
1250
.. [LazarsfeldJacobian]
1251
Robert Lazarsfeld:
1252
Positivity in algebraic geometry II;
1253
Positivity for Vector Bundles, and Multiplier Ideals,
1254
page 181.
1255
1256
EXAMPLES::
1257
1258
sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ)
1259
sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2))
1260
sage: twisted_cubic.Jacobian()
1261
Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z, x*z, -2*w*z, w*y, 3*w*y, -2*w*x,
1262
w^2, y*z, -2*x*z, w*z, 3*w*z, -2*w*y, w*x, z^2, -2*y*z, x*z, 3*x*z, -2*w*z,
1263
w*y) of Multivariate Polynomial Ring in w, x, y, z over Rational Field
1264
sage: twisted_cubic.defining_ideal()
1265
Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z) of Multivariate Polynomial Ring
1266
in w, x, y, z over Rational Field
1267
"""
1268
d = self.codimension()
1269
minors = self.Jacobian_matrix().minors(d)
1270
I = self.defining_ideal()
1271
minors = tuple([ I.reduce(m) for m in minors ])
1272
return I.ring().ideal(I.gens() + minors)
1273
1274
def reduce(self):
1275
r"""
1276
Return the corresponding reduced algebraic space associated to this
1277
scheme.
1278
1279
EXAMPLES: First we construct the union of a doubled and tripled
1280
line in the affine plane over `\QQ` ::
1281
1282
sage: A.<x,y> = AffineSpace(2, QQ)
1283
sage: X = A.subscheme([(x-1)^2*(x-y)^3]); X
1284
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1285
x^5 - 3*x^4*y + 3*x^3*y^2 - x^2*y^3 - 2*x^4 + 6*x^3*y
1286
- 6*x^2*y^2 + 2*x*y^3 + x^3 - 3*x^2*y + 3*x*y^2 - y^3
1287
sage: X.dimension()
1288
1
1289
1290
Then we compute the corresponding reduced scheme::
1291
1292
sage: Y = X.reduce(); Y
1293
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1294
x^2 - x*y - x + y
1295
1296
Finally, we verify that the reduced scheme `Y` is the union
1297
of those two lines::
1298
1299
sage: L1 = A.subscheme([x-1]); L1
1300
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1301
x - 1
1302
sage: L2 = A.subscheme([x-y]); L2
1303
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1304
x - y
1305
sage: W = L1.union(L2); W # taken in ambient space
1306
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1307
x^2 - x*y - x + y
1308
sage: Y == W
1309
True
1310
"""
1311
try:
1312
return self._reduce
1313
except AttributeError:
1314
r = self.defining_ideal().radical()
1315
A = self.ambient_space()
1316
V = A.subscheme(r)
1317
V._reduce = V # so knows it is already reduced!
1318
self._reduce = V
1319
return V
1320
1321
def union(self, other):
1322
"""
1323
Return the scheme-theoretic union of self and other in their common
1324
ambient space.
1325
1326
EXAMPLES: We construct the union of a line and a tripled-point on
1327
the line.
1328
1329
::
1330
1331
sage: A.<x,y> = AffineSpace(2, QQ)
1332
sage: I = ideal([x,y])^3
1333
sage: P = A.subscheme(I)
1334
sage: L = A.subscheme([y-1])
1335
sage: S = L.union(P); S
1336
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1337
y^4 - y^3,
1338
x*y^3 - x*y^2,
1339
x^2*y^2 - x^2*y,
1340
x^3*y - x^3
1341
sage: S.dimension()
1342
1
1343
sage: S.reduce()
1344
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1345
y^2 - y,
1346
x*y - x
1347
1348
We can also use the notation "+" for the union::
1349
1350
sage: A.subscheme([x]) + A.subscheme([y^2 - (x^3+1)])
1351
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1352
x^4 - x*y^2 + x
1353
1354
Saving and loading::
1355
1356
sage: loads(S.dumps()) == S
1357
True
1358
"""
1359
if not isinstance(other, AlgebraicScheme_subscheme):
1360
raise TypeError, "other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1361
A = self.ambient_space()
1362
if other.ambient_space() != A:
1363
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1364
return A.subscheme(self.defining_ideal().intersection(other.defining_ideal()))
1365
1366
__add__ = union
1367
1368
def intersection(self, other):
1369
"""
1370
Return the scheme-theoretic intersection of self and other in their
1371
common ambient space.
1372
1373
EXAMPLES::
1374
1375
sage: A.<x, y> = AffineSpace(2, ZZ)
1376
sage: X = A.subscheme([x^2-y])
1377
sage: Y = A.subscheme([y])
1378
sage: X.intersection(Y)
1379
Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by:
1380
x^2 - y,
1381
y
1382
"""
1383
if not isinstance(other, AlgebraicScheme_subscheme):
1384
raise TypeError, "other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1385
A = self.ambient_space()
1386
if other.ambient_space() != A:
1387
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1388
return A.subscheme(self.defining_ideal() + other.defining_ideal())
1389
1390
def complement(self, other=None):
1391
"""
1392
Return the scheme-theoretic complement other - self, where
1393
self and other are both closed algebraic subschemes of the
1394
same ambient space.
1395
1396
If other is unspecified, it is taken to be the ambient space
1397
of self.
1398
1399
EXAMPLES::
1400
1401
sage: A.<x, y, z> = AffineSpace(3, ZZ)
1402
sage: X = A.subscheme([x+y-z])
1403
sage: Y = A.subscheme([x-y+z])
1404
sage: Y.complement(X)
1405
Quasi-affine subscheme X - Y of Affine Space of
1406
dimension 3 over Integer Ring, where X is defined by:
1407
x + y - z
1408
and Y is defined by:
1409
x - y + z
1410
sage: Y.complement()
1411
Quasi-affine subscheme X - Y of Affine Space of
1412
dimension 3 over Integer Ring, where X is defined by:
1413
(no polynomials)
1414
and Y is defined by:
1415
x - y + z
1416
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
1417
sage: X = P.subscheme([x^2+y^2+z^2])
1418
sage: Y = P.subscheme([x*y+y*z+z*x])
1419
sage: Y.complement(X)
1420
Quasi-projective subscheme X - Y of Projective Space of
1421
dimension 2 over Rational Field, where X is defined by:
1422
x^2 + y^2 + z^2
1423
and Y is defined by:
1424
x*y + x*z + y*z
1425
sage: Y.complement(P)
1426
Quasi-projective subscheme X - Y of Projective Space of
1427
dimension 2 over Rational Field, where X is defined by:
1428
(no polynomials)
1429
and Y is defined by:
1430
x*y + x*z + y*z
1431
"""
1432
A = self.ambient_space()
1433
if other is None:
1434
other = A.subscheme([])
1435
elif not isinstance(other, AlgebraicScheme_subscheme):
1436
if other == A:
1437
other = A.subscheme([])
1438
else:
1439
raise TypeError, \
1440
"Argument other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1441
if other.ambient_space() != A:
1442
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1443
return AlgebraicScheme_quasi(other, self)
1444
1445
def rational_points(self, F=None, bound=0):
1446
"""
1447
Return the rational points on the algebraic subscheme.
1448
1449
EXAMPLES:
1450
1451
One can enumerate points up to a given bound on a projective scheme
1452
over the rationals::
1453
1454
sage: E = EllipticCurve('37a')
1455
sage: E.rational_points(bound=8)
1456
[(-1 : -1 : 1), (-1 : 0 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 0), (1/4 : -5/8 : 1), (1/4 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1), (2 : -3 : 1), (2 : 2 : 1)]
1457
1458
For a small finite field, the complete set of points can be
1459
enumerated. ::
1460
1461
sage: Etilde = E.base_extend(GF(3))
1462
sage: Etilde.rational_points()
1463
[(0 : 0 : 1), (0 : 1 : 0), (0 : 2 : 1), (1 : 0 : 1),
1464
(1 : 2 : 1), (2 : 0 : 1), (2 : 2 : 1)]
1465
1466
The class of hyperelliptic curves does not (yet) support
1467
desingularization of the places at infinity into two points::
1468
1469
sage: FF = FiniteField(7)
1470
sage: P.<x> = PolynomialRing(FiniteField(7))
1471
sage: C = HyperellipticCurve(x^8+x+1)
1472
sage: C.rational_points()
1473
[(0 : 1 : 0), (0 : 1 : 1), (0 : 6 : 1), (2 : 0 : 1),
1474
(4 : 0 : 1), (6 : 1 : 1), (6 : 6 : 1)]
1475
1476
TODO:
1477
1478
1. The above algorithms enumerate all projective points and
1479
test whether they lie on the scheme; Implement a more naive
1480
sieve at least for covers of the projective line.
1481
1482
2. Implement Stoll's model in weighted projective space to
1483
resolve singularities and find two points (1 : 1 : 0) and
1484
(-1 : 1 : 0) at infinity.
1485
"""
1486
if F == None:
1487
F = self.base_ring()
1488
X = self(F)
1489
if is_RationalField(F) or F == ZZ:
1490
if not bound > 0:
1491
raise TypeError, "A positive bound (= %s) must be specified."%bound
1492
try:
1493
return X.points(bound)
1494
except TypeError:
1495
raise TypeError, "Unable to enumerate points over %s."%F
1496
try:
1497
return X.points()
1498
except TypeError:
1499
raise TypeError, "Unable to enumerate points over %s."%F
1500
1501
def change_ring(self,R):
1502
r"""
1503
Returns a new projective subscheme whose base ring is self coerced to R.
1504
1505
EXAMPLES::
1506
1507
sage: P.<x,y>=ProjectiveSpace(QQ,1)
1508
sage: X=P.subscheme([3*x^2-y^2])
1509
sage: H=Hom(X,X)
1510
sage: X.change_ring(GF(3))
1511
Closed subscheme of Projective Space of dimension 1 over Finite Field of size 3 defined by:
1512
-y^2
1513
"""
1514
A=self.ambient_space().change_ring(R)
1515
I=self.defining_ideal().change_ring(A.coordinate_ring())
1516
return(A.subscheme(I))
1517
1518
#*******************************************************************
1519
# Affine varieties
1520
#*******************************************************************
1521
class AlgebraicScheme_subscheme_affine(AlgebraicScheme_subscheme):
1522
"""
1523
Construct an algebraic subscheme of affine space.
1524
1525
.. WARNING::
1526
1527
You should not create objects of this class directly. The
1528
preferred method to construct such subschemes is to use
1529
:meth:`~sage.schemes.affine.affine_space.AffineSpace_generic.subscheme`
1530
method of :class:`affine space
1531
<sage.schemes.affine.affine_space.AffineSpace_generic>`.
1532
1533
INPUT:
1534
1535
- ``A`` -- ambient :class:`affine space
1536
<sage.schemes.affine.affine_space.AffineSpace_generic>`
1537
1538
- ``polynomials`` -- single polynomial, ideal or iterable of
1539
defining polynomials.
1540
1541
EXAMPLES::
1542
1543
sage: A3.<x, y, z> = AffineSpace(3, QQ)
1544
sage: A3.subscheme([x^2-y*z])
1545
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
1546
x^2 - y*z
1547
1548
TESTS::
1549
1550
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme_affine
1551
sage: AlgebraicScheme_subscheme_affine(A3, [x^2-y*z])
1552
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
1553
x^2 - y*z
1554
"""
1555
1556
def _morphism(self, *args, **kwds):
1557
"""
1558
A morphism between two schemes in your category, usually defined via
1559
polynomials. Your morphism class should derive from
1560
:class:`SchemeMorphism_polynomial`. These morphisms will usually be
1561
elements of the Hom-set
1562
:class:`~sage.schemes.generic.homset.SchemeHomset_generic`.
1563
1564
EXAMPLES::
1565
1566
sage: P2.<x,y,z> = ProjectiveSpace(2, ZZ)
1567
sage: P2._morphism(P2.Hom(P2), [x,y,z])
1568
Scheme endomorphism of Projective Space of dimension 2 over Integer Ring
1569
Defn: Defined on coordinates by sending (x : y : z) to
1570
(x : y : z)
1571
1572
"""
1573
return self.ambient_space()._morphism(*args, **kwds)
1574
1575
def dimension(self):
1576
"""
1577
Return the dimension of the affine algebraic subscheme.
1578
1579
OUTPUT:
1580
1581
Integer.
1582
1583
EXAMPLES::
1584
1585
sage: A.<x,y> = AffineSpace(2, QQ)
1586
sage: A.subscheme([]).dimension()
1587
2
1588
sage: A.subscheme([x]).dimension()
1589
1
1590
sage: A.subscheme([x^5]).dimension()
1591
1
1592
sage: A.subscheme([x^2 + y^2 - 1]).dimension()
1593
1
1594
sage: A.subscheme([x*(x-1), y*(y-1)]).dimension()
1595
0
1596
1597
Something less obvious::
1598
1599
sage: A.<x,y,z,w> = AffineSpace(4, QQ)
1600
sage: X = A.subscheme([x^2, x^2*y^2 + z^2, z^2 - w^2, 10*x^2 + w^2 - z^2])
1601
sage: X
1602
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
1603
x^2,
1604
x^2*y^2 + z^2,
1605
z^2 - w^2,
1606
10*x^2 - z^2 + w^2
1607
sage: X.dimension()
1608
1
1609
"""
1610
try:
1611
return self.__dimension
1612
except AttributeError:
1613
self.__dimension = self.defining_ideal().dimension()
1614
return self.__dimension
1615
1616
def projective_embedding(self, i=None, X=None):
1617
"""
1618
Returns a morphism from this affine scheme into an ambient
1619
projective space of the same dimension.
1620
1621
INPUT:
1622
1623
- ``i`` -- integer (default: dimension of self = last
1624
coordinate) determines which projective embedding to compute. The
1625
embedding is that which has a 1 in the i-th coordinate, numbered
1626
from 0.
1627
1628
1629
- ``X`` -- (default: None) projective scheme, i.e., codomain of
1630
morphism; this is constructed if it is not given.
1631
1632
EXAMPLES::
1633
1634
sage: A.<x, y, z> = AffineSpace(3, ZZ)
1635
sage: S = A.subscheme([x*y-z])
1636
sage: S.projective_embedding()
1637
Scheme morphism:
1638
From: Closed subscheme of Affine Space of dimension 3 over Integer Ring defined by:
1639
x*y - z
1640
To: Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by:
1641
x0*x1 - x2*x3
1642
Defn: Defined on coordinates by sending (x, y, z) to
1643
(x : y : z : 1)
1644
"""
1645
AA = self.ambient_space()
1646
n = AA.dimension_relative()
1647
if i is None:
1648
try:
1649
i = self._default_embedding_index
1650
except AttributeError:
1651
i = int(n)
1652
else:
1653
i = int(i)
1654
if i < 0 or i > n:
1655
raise ValueError, \
1656
"Argument i (=%s) must be between 0 and %s, inclusive"%(i, n)
1657
try:
1658
return self.__projective_embedding[i]
1659
except AttributeError:
1660
self.__projective_embedding = {}
1661
except KeyError:
1662
pass
1663
if X is None:
1664
PP = sage.schemes.projective.projective_space.ProjectiveSpace(n, AA.base_ring())
1665
v = list(PP.gens())
1666
z = v.pop(i)
1667
v.append(z)
1668
polys = self.defining_polynomials()
1669
X = PP.subscheme([ f.homogenize()(v) for f in polys ])
1670
R = AA.coordinate_ring()
1671
v = list(R.gens())
1672
v.insert(i, R(1))
1673
phi = self.hom(v, X)
1674
self.__projective_embedding[i] = phi
1675
return phi
1676
1677
def is_smooth(self, point=None):
1678
r"""
1679
Test whether the algebraic subscheme is smooth.
1680
1681
INPUT:
1682
1683
- ``point`` -- A point or ``None`` (default). The point to
1684
test smoothness at.
1685
1686
OUTPUT:
1687
1688
Boolean. If no point was specified, returns whether the
1689
algebraic subscheme is smooth everywhere. Otherwise,
1690
smoothness at the specified point is tested.
1691
1692
EXAMPLES::
1693
1694
sage: A2.<x,y> = AffineSpace(2,QQ)
1695
sage: cuspidal_curve = A2.subscheme([y^2-x^3])
1696
sage: cuspidal_curve
1697
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1698
-x^3 + y^2
1699
sage: smooth_point = cuspidal_curve.point([1,1])
1700
sage: smooth_point in cuspidal_curve
1701
True
1702
sage: singular_point = cuspidal_curve.point([0,0])
1703
sage: singular_point in cuspidal_curve
1704
True
1705
sage: cuspidal_curve.is_smooth(smooth_point)
1706
True
1707
sage: cuspidal_curve.is_smooth(singular_point)
1708
False
1709
sage: cuspidal_curve.is_smooth()
1710
False
1711
"""
1712
R = self.ambient_space().coordinate_ring()
1713
if not point is None:
1714
self._check_satisfies_equations(point)
1715
point_subs = dict(zip(R.gens(), point))
1716
Jac = self.Jacobian().subs(point_subs)
1717
return not Jac.is_zero()
1718
1719
# testing smoothness everywhere tends to be expensive
1720
try:
1721
return self._smooth
1722
except AttributeError:
1723
pass
1724
sing_dim = self.Jacobian().dimension()
1725
self._smooth = (sing_dim == -1)
1726
return self._smooth
1727
1728
1729
1730
#*******************************************************************
1731
# Projective varieties
1732
#*******************************************************************
1733
class AlgebraicScheme_subscheme_projective(AlgebraicScheme_subscheme):
1734
"""
1735
Construct an algebraic subscheme of projective space.
1736
1737
.. WARNING::
1738
1739
You should not create objects of this class directly. The
1740
preferred method to construct such subschemes is to use
1741
:meth:`~sage.schemes.projective.projective_space.ProjectiveSpace_field.subscheme`
1742
method of :class:`projective space
1743
<sage.schemes.projective.projective_space.ProjectiveSpace_field>`.
1744
1745
INPUT:
1746
1747
- ``A`` -- ambient :class:`projective space
1748
<sage.schemes.projective.projective_space.ProjectiveSpace_field>`.
1749
1750
- ``polynomials`` -- single polynomial, ideal or iterable of
1751
defining homogeneous polynomials.
1752
1753
EXAMPLES::
1754
1755
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
1756
sage: P.subscheme([x^2-y*z])
1757
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1758
x^2 - y*z
1759
1760
TESTS::
1761
1762
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme_projective
1763
sage: AlgebraicScheme_subscheme_projective(P, [x^2-y*z])
1764
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1765
x^2 - y*z
1766
"""
1767
1768
def _morphism(self, *args, **kwds):
1769
r"""
1770
Construct a morphism determined by action on points of ``self``.
1771
1772
For internal use only.
1773
1774
INPUT:
1775
1776
- same as for
1777
:class:`~sage.schemes.projective.projective_morphism.SchemeMorphism_polynomial_projective_space`.
1778
1779
OUPUT:
1780
1781
- :class:`~sage.schemes.projective.projective_morphism.SchemeMorphism_polynomial_projective_space`.
1782
1783
TESTS::
1784
1785
sage: P1.<x,y> = ProjectiveSpace(1,QQ)
1786
sage: P2 = ProjectiveSpace(2,QQ)
1787
sage: H12 = P1.Hom(P2)
1788
sage: H12([x^2,x*y, y^2]) # indirect doctest
1789
Scheme morphism:
1790
From: Projective Space of dimension 1 over Rational Field
1791
To: Projective Space of dimension 2 over Rational Field
1792
Defn: Defined on coordinates by sending (x : y) to
1793
(x^2 : x*y : y^2)
1794
sage: P1._morphism(H12, [x^2,x*y, y^2])
1795
Scheme morphism:
1796
From: Projective Space of dimension 1 over Rational Field
1797
To: Projective Space of dimension 2 over Rational Field
1798
Defn: Defined on coordinates by sending (x : y) to
1799
(x^2 : x*y : y^2)
1800
"""
1801
return self.ambient_space()._morphism(*args, **kwds)
1802
1803
def dimension(self):
1804
"""
1805
Return the dimension of the projective algebraic subscheme.
1806
1807
OUTPUT:
1808
1809
Integer.
1810
1811
EXAMPLES::
1812
1813
sage: P2.<x,y,z> = ProjectiveSpace(2, QQ)
1814
sage: P2.subscheme([]).dimension()
1815
2
1816
sage: P2.subscheme([x]).dimension()
1817
1
1818
sage: P2.subscheme([x^5]).dimension()
1819
1
1820
sage: P2.subscheme([x^2 + y^2 - z^2]).dimension()
1821
1
1822
sage: P2.subscheme([x*(x-z), y*(y-z)]).dimension()
1823
0
1824
1825
Something less obvious::
1826
1827
sage: P3.<x,y,z,w,t> = ProjectiveSpace(4, QQ)
1828
sage: X = P3.subscheme([x^2, x^2*y^2 + z^2*t^2, z^2 - w^2, 10*x^2 + w^2 - z^2])
1829
sage: X
1830
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1831
x^2,
1832
x^2*y^2 + z^2*t^2,
1833
z^2 - w^2,
1834
10*x^2 - z^2 + w^2
1835
sage: X.dimension()
1836
1
1837
"""
1838
try:
1839
return self.__dimension
1840
except AttributeError:
1841
self.__dimension = self.defining_ideal().dimension() - 1
1842
return self.__dimension
1843
1844
def affine_patch(self, i):
1845
r"""
1846
Return the `i^{th}` affine patch of this projective scheme.
1847
This is the intersection with this `i^{th}` affine patch of
1848
its ambient space.
1849
1850
INPUT:
1851
1852
- ``i`` -- integer between 0 and dimension of self, inclusive.
1853
1854
OUTPUT:
1855
1856
An affine algebraic scheme with fixed
1857
:meth:`embedding_morphism` equal to the default
1858
:meth:`projective_embedding` map`.
1859
1860
EXAMPLES::
1861
1862
sage: PP = ProjectiveSpace(2, QQ, names='X,Y,Z')
1863
sage: X,Y,Z = PP.gens()
1864
sage: C = PP.subscheme(X^3*Y + Y^3*Z + Z^3*X)
1865
sage: U = C.affine_patch(0)
1866
sage: U
1867
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1868
x0^3*x1 + x1^3 + x0
1869
sage: U.embedding_morphism()
1870
Scheme morphism:
1871
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1872
x0^3*x1 + x1^3 + x0
1873
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1874
X^3*Y + Y^3*Z + X*Z^3
1875
Defn: Defined on coordinates by sending (x0, x1) to
1876
(1 : x0 : x1)
1877
sage: U.projective_embedding() is U.embedding_morphism()
1878
True
1879
"""
1880
i = int(i) # implicit type checking
1881
PP = self.ambient_space()
1882
n = PP.dimension()
1883
if i < 0 or i > n:
1884
raise ValueError, "Argument i (= %s) must be between 0 and %s."%(i, n)
1885
try:
1886
return self.__affine_patches[i]
1887
except AttributeError:
1888
self.__affine_patches = {}
1889
except KeyError:
1890
pass
1891
AA = PP.affine_patch(i)
1892
phi = AA.projective_embedding()
1893
polys = self.defining_polynomials()
1894
xi = phi.defining_polynomials()
1895
U = AA.subscheme([ f(xi) for f in polys ])
1896
U._default_embedding_index = i
1897
phi = U.projective_embedding(i, self)
1898
self.__affine_patches[i] = U
1899
U._embedding_morphism = phi
1900
return U
1901
1902
def _best_affine_patch(self, point):
1903
r"""
1904
Return the best affine patch of the ambient projective space.
1905
1906
The "best" affine patch is where you end up dividing by the
1907
homogeneous coordinate with the largest absolutue
1908
value. Division by small numbers is numerically unstable.
1909
1910
INPUT:
1911
1912
- ``point`` -- a point of the algebraic subscheme.
1913
1914
OUTPUT:
1915
1916
Integer. The index of the patch. See :meth:`affine_patch`.
1917
1918
EXAMPLES::
1919
1920
sage: P.<x,y,z>= ProjectiveSpace(QQ,2)
1921
sage: S = P.subscheme(x+2*y+3*z)
1922
sage: S._best_affine_patch(P.point([0,-3,2]))
1923
1
1924
sage: S._best_affine_patch([0,-3,2])
1925
1
1926
1927
TESTS::
1928
1929
sage: F = GF(3)
1930
sage: P.<x,y,z>= ProjectiveSpace(F,2)
1931
sage: S._best_affine_patch([0,1,2])
1932
2
1933
"""
1934
point = list(point)
1935
try:
1936
abs_point = map(abs, point)
1937
except ArithmeticError:
1938
# our base ring does not know abs
1939
abs_point = point
1940
# find best patch
1941
i_max = 0
1942
p_max = abs_point[i_max]
1943
for i in range(1,len(point)):
1944
if abs_point[i]>p_max:
1945
i_max = i
1946
p_max = abs_point[i_max]
1947
return i_max
1948
1949
def neighborhood(self, point):
1950
r"""
1951
Return an affine algebraic subscheme isomorphic to a
1952
neighborhood of the ``point``.
1953
1954
INPUT:
1955
1956
- ``point`` -- a point of the projective subscheme.
1957
1958
OUTPUT
1959
1960
An affine algebraic scheme (polynomial equations in affine
1961
space) ``result`` such that
1962
1963
* :meth:`embedding_morphism
1964
<AlgebraicScheme.embedding_morphism>` is an isomorphism to a
1965
neighborhood of ``point``
1966
1967
* :meth:`embedding_center <AlgebraicScheme.embedding_center>`
1968
is mapped to ``point``.
1969
1970
EXAMPLES::
1971
1972
sage: P.<x,y,z>= ProjectiveSpace(QQ,2)
1973
sage: S = P.subscheme(x+2*y+3*z)
1974
sage: s = S.point([0,-3,2]); s
1975
(0 : -3/2 : 1)
1976
sage: patch = S.neighborhood(s); patch
1977
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1978
x0 + 3*x1
1979
sage: patch.embedding_morphism()
1980
Scheme morphism:
1981
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1982
x0 + 3*x1
1983
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1984
x + 2*y + 3*z
1985
Defn: Defined on coordinates by sending (x0, x1) to
1986
(x0 : -3/2 : x1 + 1)
1987
sage: patch.embedding_center()
1988
(0, 0)
1989
sage: patch.embedding_morphism()([0,0])
1990
(0 : -3/2 : 1)
1991
sage: patch.embedding_morphism()(patch.embedding_center())
1992
(0 : -3/2 : 1)
1993
"""
1994
point = list(point)
1995
self._check_satisfies_equations(point)
1996
PP = self.ambient_space()
1997
n = PP.dimension()
1998
i = self._best_affine_patch(point)
1999
2000
patch_cover = PP.affine_patch(i)
2001
R = patch_cover.coordinate_ring()
2002
2003
phi = list(point)
2004
for j in range(0,i):
2005
phi[j] = phi[j] + R.gen(j)
2006
for j in range(i,n):
2007
phi[j+1] = phi[j+1] + R.gen(j)
2008
2009
pullback_polys = [f(phi) for f in self.defining_polynomials()]
2010
patch = patch_cover.subscheme(pullback_polys)
2011
patch_hom = patch.hom(phi,self)
2012
patch._embedding_center = patch.point([0]*n)
2013
patch._embedding_morphism = patch_hom
2014
return patch
2015
2016
def is_smooth(self, point=None):
2017
r"""
2018
Test whether the algebraic subscheme is smooth.
2019
2020
INPUT:
2021
2022
- ``point`` -- A point or ``None`` (default). The point to
2023
test smoothness at.
2024
2025
OUTPUT:
2026
2027
Boolean. If no point was specified, returns whether the
2028
algebraic subscheme is smooth everywhere. Otherwise,
2029
smoothness at the specified point is tested.
2030
2031
EXAMPLES::
2032
2033
sage: P2.<x,y,z> = ProjectiveSpace(2,QQ)
2034
sage: cuspidal_curve = P2.subscheme([y^2*z-x^3])
2035
sage: cuspidal_curve
2036
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
2037
-x^3 + y^2*z
2038
sage: cuspidal_curve.is_smooth([1,1,1])
2039
True
2040
sage: cuspidal_curve.is_smooth([0,0,1])
2041
False
2042
sage: cuspidal_curve.is_smooth()
2043
False
2044
sage: P2.subscheme([y^2*z-x^3+z^3+1/10*x*y*z]).is_smooth()
2045
True
2046
2047
TESTS::
2048
2049
sage: H = P2.subscheme(x)
2050
sage: H.is_smooth() # one of the few cases where the cone over the subvariety is smooth
2051
True
2052
"""
2053
if not point is None:
2054
self._check_satisfies_equations(point)
2055
R = self.ambient_space().coordinate_ring()
2056
point_subs = dict(zip(R.gens(), point))
2057
Jac = self.Jacobian().subs(point_subs)
2058
return not Jac.is_zero()
2059
2060
# testing smoothness everywhere tends to be expensive
2061
try:
2062
return self._smooth
2063
except AttributeError:
2064
pass
2065
sing_dim = self.Jacobian().dimension()
2066
# We really test the affine cone here; the origin is always a singular point:
2067
self._smooth = (sing_dim <= 0)
2068
return self._smooth
2069
2070
2071
#*******************************************************************
2072
# Toric varieties
2073
#*******************************************************************
2074
class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme):
2075
r"""
2076
Construct an algebraic subscheme of a toric variety.
2077
2078
.. WARNING::
2079
2080
You should not create objects of this class directly. The
2081
preferred method to construct such subschemes is to use
2082
:meth:`~ToricVariety_field.subscheme` method of :class:`toric
2083
varieties
2084
<sage.schemes.toric.variety.ToricVariety_field>`.
2085
2086
INPUT:
2087
2088
- ``toric_variety`` -- ambient :class:`toric variety
2089
<ToricVariety_field>`;
2090
2091
- ``polynomials`` -- single polynomial, list, or ideal of defining
2092
polynomials in the coordinate ring of ``toric_variety``.
2093
2094
OUTPUT:
2095
2096
- :class:`algebraic subscheme of a toric variety
2097
<AlgebraicScheme_subscheme_toric>`.
2098
2099
TESTS::
2100
2101
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2102
sage: P1xP1 = ToricVariety(fan, "x s y t")
2103
sage: P1xP1.inject_variables()
2104
Defining x, s, y, t
2105
sage: import sage.schemes.generic.algebraic_scheme as SCM
2106
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2107
... P1xP1, [x*s + y*t, x^3+y^3])
2108
sage: X
2109
Closed subscheme of 2-d toric variety
2110
covered by 4 affine patches defined by:
2111
x*s + y*t,
2112
x^3 + y^3
2113
2114
A better way to construct the same scheme as above::
2115
2116
sage: P1xP1.subscheme([x*s + y*t, x^3+y^3])
2117
Closed subscheme of 2-d toric variety
2118
covered by 4 affine patches defined by:
2119
x*s + y*t,
2120
x^3 + y^3
2121
"""
2122
2123
# Implementation note: if the toric variety is affine you should
2124
# construct instances of the derived class
2125
# AlgebraicScheme_subscheme_affine_toric instead.
2126
2127
def __init__(self, toric_variety, polynomials):
2128
r"""
2129
See :class:`AlgebraicScheme_subscheme_toric` for documentation.
2130
2131
TESTS::
2132
2133
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2134
sage: P1xP1 = ToricVariety(fan, "x s y t")
2135
sage: P1xP1.inject_variables()
2136
Defining x, s, y, t
2137
sage: import sage.schemes.generic.algebraic_scheme as SCM
2138
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2139
... P1xP1, [x*s + y*t, x^3+y^3])
2140
sage: X
2141
Closed subscheme of 2-d toric variety
2142
covered by 4 affine patches defined by:
2143
x*s + y*t,
2144
x^3 + y^3
2145
"""
2146
# Just to make sure that keyword arguments will be passed correctly
2147
super(AlgebraicScheme_subscheme_toric, self).__init__(toric_variety,
2148
polynomials)
2149
2150
def _morphism(self, *args, **kwds):
2151
r"""
2152
Construct a morphism determined by action on points of ``self``.
2153
2154
INPUT:
2155
2156
- same as for
2157
:class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`.
2158
2159
OUPUT:
2160
2161
- :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`.
2162
2163
TESTS::
2164
2165
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2166
sage: P1xP1 = ToricVariety(fan)
2167
sage: P1xP1.inject_variables()
2168
Defining z0, z1, z2, z3
2169
sage: P1 = P1xP1.subscheme(z0-z2)
2170
sage: H = P1.Hom(P1xP1)
2171
sage: H([z0,z1,z0,z3])
2172
Scheme morphism:
2173
From: Closed subscheme of 2-d toric variety
2174
covered by 4 affine patches defined by:
2175
z0 - z2
2176
To: 2-d toric variety covered by 4 affine patches
2177
Defn: Defined on coordinates by sending [z0 : z1 : z2 : z3] to
2178
[z2 : z1 : z2 : z3]
2179
2180
sage: P1._morphism(H, [z0,z1,z0,z3])
2181
Scheme morphism:
2182
From: Closed subscheme of 2-d toric variety
2183
covered by 4 affine patches defined by:
2184
z0 - z2
2185
To: 2-d toric variety covered by 4 affine patches
2186
Defn: Defined on coordinates by sending [z0 : z1 : z2 : z3] to
2187
[z2 : z1 : z2 : z3]
2188
"""
2189
from sage.schemes.toric.morphism import SchemeMorphism_polynomial_toric_variety
2190
return SchemeMorphism_polynomial_toric_variety(*args, **kwds)
2191
2192
def _point_homset(self, *args, **kwds):
2193
r"""
2194
Construct a Hom-set for ``self``.
2195
2196
INPUT:
2197
2198
- same as for
2199
:class:`~sage.schemes.generic.homset.SchemeHomset_points_toric_field`.
2200
2201
OUPUT:
2202
2203
:class:`~sage.schemes.toric.homset.SchemeHomset_points_subscheme_toric_field`.
2204
2205
TESTS::
2206
2207
sage: P2.<x,y,z> = toric_varieties.P2()
2208
sage: quadric = P2.subscheme([x^2 + y^2 + z^2])
2209
sage: quadric._point_homset(Spec(QQ), quadric)
2210
Set of rational points of Closed subscheme of 2-d CPR-Fano
2211
toric variety covered by 3 affine patches defined by:
2212
x^2 + y^2 + z^2
2213
sage: type(quadric.point_set())
2214
<class 'sage.schemes.toric.homset.SchemeHomset_points_subscheme_toric_field_with_category'>
2215
"""
2216
from sage.schemes.toric.homset import SchemeHomset_points_subscheme_toric_field
2217
return SchemeHomset_points_subscheme_toric_field(*args, **kwds)
2218
2219
def fan(self):
2220
"""
2221
Return the fan of the ambient space.
2222
2223
OUTPUT:
2224
2225
A fan.
2226
2227
EXAMPLES::
2228
2229
sage: P2.<x,y,z> = toric_varieties.P(2)
2230
sage: E = P2.subscheme([x^2+y^2+z^2])
2231
sage: E.fan()
2232
Rational polyhedral fan in 2-d lattice N
2233
"""
2234
return self.ambient_space().fan()
2235
2236
def affine_patch(self, i):
2237
r"""
2238
Return the ``i``-th affine patch of ``self`` as an affine
2239
toric algebraic scheme.
2240
2241
INPUT:
2242
2243
- ``i`` -- integer, index of a generating cone of the fan of the
2244
ambient space of ``self``.
2245
2246
OUTPUT:
2247
2248
- subscheme of an affine :class:`toric variety
2249
<sage.schemes.toric.variety.ToricVariety_field>`
2250
corresponding to the pull-back of ``self`` by the embedding
2251
morphism of the ``i``-th :meth:`affine patch of the ambient
2252
space
2253
<sage.schemes.toric.variety.ToricVariety_field.affine_patch>`
2254
of ``self``.
2255
2256
The result is cached, so the ``i``-th patch is always the same object
2257
in memory.
2258
2259
EXAMPLES::
2260
2261
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2262
sage: P1xP1 = ToricVariety(fan, "x s y t")
2263
sage: patch1 = P1xP1.affine_patch(1)
2264
sage: patch1.embedding_morphism()
2265
Scheme morphism:
2266
From: 2-d affine toric variety
2267
To: 2-d toric variety covered by 4 affine patches
2268
Defn: Defined on coordinates by sending [y : t] to
2269
[1 : 1 : y : t]
2270
sage: P1xP1.inject_variables()
2271
Defining x, s, y, t
2272
sage: P1 = P1xP1.subscheme(x-y)
2273
sage: subpatch = P1.affine_patch(1)
2274
sage: subpatch
2275
Closed subscheme of 2-d affine toric variety defined by:
2276
-y + 1
2277
"""
2278
i = int(i) # implicit type checking
2279
try:
2280
return self._affine_patches[i]
2281
except AttributeError:
2282
self._affine_patches = dict()
2283
except KeyError:
2284
pass
2285
ambient_patch = self.ambient_space().affine_patch(i)
2286
phi_p = ambient_patch.embedding_morphism().defining_polynomials()
2287
patch = ambient_patch.subscheme(
2288
[p(phi_p) for p in self.defining_polynomials()])
2289
patch._embedding_morphism = patch.hom(phi_p, self, check=False)
2290
self._affine_patches[i] = patch
2291
return patch
2292
2293
def affine_algebraic_patch(self, cone=None, names=None):
2294
r"""
2295
Return the affine patch corresponding to ``cone`` as an affine
2296
algebraic scheme.
2297
2298
INPUT:
2299
2300
- ``cone`` -- a :class:`Cone
2301
<sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma`
2302
of the fan. It can be omitted for an affine toric variety,
2303
in which case the single generating cone is used.
2304
2305
OUTPUT:
2306
2307
An :class:`affine algebraic subscheme
2308
<sage.schemes.generic.algebraic_scheme.AlgebraicScheme_subscheme_affine>`
2309
corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)`
2310
associated to the cone `\sigma`.
2311
2312
See also :meth:`affine_patch`, which expresses the patches as
2313
subvarieties of affine toric varieties instead.
2314
2315
REFERENCES:
2316
2317
..
2318
2319
David A. Cox, "The Homogeneous Coordinate Ring of a Toric
2320
Variety", Lemma 2.2.
2321
http://www.arxiv.org/abs/alg-geom/9210008v2
2322
2323
EXAMPLES::
2324
2325
sage: P2.<x,y,z> = toric_varieties.P2()
2326
sage: cone = P2.fan().generating_cone(0)
2327
sage: V = P2.subscheme(x^3+y^3+z^3)
2328
sage: V.affine_algebraic_patch(cone)
2329
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
2330
z0^3 + z1^3 + 1
2331
2332
sage: cone = Cone([(0,1),(2,1)])
2333
sage: A2Z2.<x,y> = AffineToricVariety(cone)
2334
sage: A2Z2.affine_algebraic_patch()
2335
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2336
-z0*z1 + z2^2
2337
sage: V = A2Z2.subscheme(x^2+y^2-1)
2338
sage: patch = V.affine_algebraic_patch(); patch
2339
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2340
-z0*z1 + z2^2,
2341
z0 + z1 - 1
2342
sage: nbhd_patch = V.neighborhood([1,0]).affine_algebraic_patch(); nbhd_patch
2343
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2344
-z0*z1 + z2^2,
2345
z0 + z1 - 1
2346
sage: nbhd_patch.embedding_center()
2347
(0, 1, 0)
2348
2349
Here we got two defining equations. The first one describes
2350
the singularity of the ambient space and the second is the
2351
pull-back of `x^2+y^2-1` ::
2352
2353
sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)])
2354
sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp)
2355
sage: Y = X.subscheme(x*v+y*u+t)
2356
sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)])
2357
sage: Y.affine_algebraic_patch(cone)
2358
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
2359
z0*z2 - z1*z3,
2360
z1 + z3 + 1
2361
"""
2362
from sage.modules.all import vector
2363
from sage.misc.all import prod
2364
ambient = self.ambient_space()
2365
fan = ambient.fan()
2366
if cone is None:
2367
assert ambient.is_affine()
2368
cone = fan.generating_cone(0)
2369
else:
2370
cone = fan.embed(cone)
2371
# R/I = C[sigma^dual cap M]
2372
R, I, dualcone = ambient._semigroup_ring(cone, names)
2373
2374
# inhomogenize the Cox homogeneous polynomial with respect to the given cone
2375
inhomogenize = dict( (ambient.coordinate_ring().gen(i), 1)
2376
for i in range(0,fan.nrays())
2377
if not i in cone.ambient_ray_indices() )
2378
polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ]
2379
2380
# map the monomial x^{D_m} to m, see reference.
2381
n_rho_matrix = cone.rays().matrix()
2382
def pullback_polynomial(p):
2383
result = R.zero()
2384
for coefficient, monomial in p:
2385
exponent = monomial.exponents()[0]
2386
exponent = [ exponent[i] for i in cone.ambient_ray_indices() ]
2387
exponent = vector(ZZ,exponent)
2388
m = n_rho_matrix.solve_right(exponent)
2389
assert all(x in ZZ for x in m), \
2390
'The polynomial '+str(p)+' does not define a ZZ-divisor!'
2391
m_coeffs = dualcone.Hilbert_coefficients(m)
2392
result += coefficient * prod(R.gen(i)**m_coeffs[i]
2393
for i in range(0,R.ngens()))
2394
return result
2395
2396
# construct the affine algebraic scheme to use as patch
2397
polynomials = map(pullback_polynomial, polynomials)
2398
patch_cover = sage.schemes.affine.affine_space.AffineSpace(R)
2399
polynomials = list(I.gens()) + polynomials
2400
polynomials = filter( lambda x:not x.is_zero(), polynomials)
2401
patch = patch_cover.subscheme(polynomials)
2402
2403
# TODO: If the cone is not smooth, then the coordinate_ring()
2404
# of the affine toric variety is wrong; it should be the
2405
# G-invariant part. So we can't construct the embedding
2406
# morphism in that case.
2407
if cone.is_smooth():
2408
x = ambient.coordinate_ring().gens()
2409
phi = []
2410
for i in range(0,fan.nrays()):
2411
if i in cone.ambient_ray_indices():
2412
phi.append(pullback_polynomial(x[i]))
2413
else:
2414
phi.append(1)
2415
patch._embedding_morphism = patch.hom(phi, self)
2416
else:
2417
patch._embedding_morphism = (NotImplementedError,
2418
'I only know how to construct embedding morphisms for smooth patches')
2419
2420
try:
2421
point = self.embedding_center()
2422
except AttributeError:
2423
return patch
2424
2425
# it remains to find the preimage of point
2426
# map m to the monomial x^{D_m}, see reference.
2427
F = ambient.coordinate_ring().fraction_field()
2428
image = []
2429
for m in dualcone.Hilbert_basis():
2430
x_Dm = prod([ F.gen(i)**(m*n) for i,n in enumerate(fan.rays()) ])
2431
image.append(x_Dm)
2432
patch._embedding_center = tuple( f(list(point)) for f in image )
2433
return patch
2434
2435
def _best_affine_patch(self, point):
2436
r"""
2437
Return the best affine patch of the ambient toric variety.
2438
2439
INPUT:
2440
2441
- ``point`` -- a point of the algebraic subscheme.
2442
2443
OUTPUT:
2444
2445
Integer. The index of the patch. See :meth:`affine_patch`.
2446
2447
EXAMPLES::
2448
2449
sage: P.<x,y,z>= toric_varieties.P2()
2450
sage: S = P.subscheme(x+2*y+3*z)
2451
sage: S._best_affine_patch(P.point([2,-3,0]))
2452
1
2453
sage: S._best_affine_patch([2,-3,0])
2454
1
2455
"""
2456
# TODO: this method should pick a "best" patch in the sense
2457
# that it is numerically stable to dehomogenize, see the
2458
# corresponding method for projective varieties.
2459
point = list(point)
2460
zeros = set(i for i, coord in enumerate(point) if coord == 0)
2461
for cone_idx, cone in enumerate(self.ambient_space().fan().generating_cones()):
2462
if zeros.issubset(cone.ambient_ray_indices()):
2463
return cone_idx
2464
assert False, 'The point must not have been a point of the toric variety.'
2465
2466
def neighborhood(self, point):
2467
r"""
2468
Return an toric algebraic scheme isomorphic to neighborhood of
2469
the ``point``.
2470
2471
INPUT:
2472
2473
- ``point`` -- a point of the toric algebraic scheme.
2474
2475
OUTPUT
2476
2477
An affine toric algebraic scheme (polynomial equations in an
2478
affine toric variety) with fixed
2479
:meth:`~AlgebraicScheme.embedding_morphism` and
2480
:meth:`~AlgebraicScheme.embedding_center`.
2481
2482
EXAMPLES::
2483
2484
sage: P.<x,y,z>= toric_varieties.P2()
2485
sage: S = P.subscheme(x+2*y+3*z)
2486
sage: s = S.point([0,-3,2]); s
2487
[0 : -3 : 2]
2488
sage: patch = S.neighborhood(s); patch
2489
Closed subscheme of 2-d affine toric variety defined by:
2490
x + 2*y + 6
2491
sage: patch.embedding_morphism()
2492
Scheme morphism:
2493
From: Closed subscheme of 2-d affine toric variety defined by:
2494
x + 2*y + 6
2495
To: Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by:
2496
x + 2*y + 3*z
2497
Defn: Defined on coordinates by sending [x : y] to
2498
[-2*y - 6 : y : 2]
2499
sage: patch.embedding_center()
2500
[0 : -3]
2501
sage: patch.embedding_morphism()(patch.embedding_center())
2502
[0 : -3 : 2]
2503
2504
A more complicated example::
2505
2506
sage: dP6.<x0,x1,x2,x3,x4,x5> = toric_varieties.dP6()
2507
sage: twoP1 = dP6.subscheme(x0*x3)
2508
sage: patch = twoP1.neighborhood([0,1,2, 3,4,5]); patch
2509
Closed subscheme of 2-d affine toric variety defined by:
2510
3*x0
2511
sage: patch.embedding_morphism()
2512
Scheme morphism:
2513
From: Closed subscheme of 2-d affine toric variety defined by:
2514
3*x0
2515
To: Closed subscheme of 2-d CPR-Fano toric variety covered by 6 affine patches defined by:
2516
x0*x3
2517
Defn: Defined on coordinates by sending [x0 : x1] to
2518
[0 : x1 : 2 : 3 : 4 : 5]
2519
sage: patch.embedding_center()
2520
[0 : 1]
2521
sage: patch.embedding_morphism()(patch.embedding_center())
2522
[0 : 1 : 2 : 3 : 4 : 5]
2523
"""
2524
point = list(point)
2525
self._check_satisfies_equations(point)
2526
PP = self.ambient_space()
2527
n = PP.dimension()
2528
fan = PP.fan()
2529
cone_idx = self._best_affine_patch(point)
2530
cone = fan.generating_cone(cone_idx)
2531
2532
patch_cover = PP.affine_patch(cone_idx)
2533
R = patch_cover.coordinate_ring()
2534
phi = []
2535
point_preimage = []
2536
for i in range(0,fan.nrays()):
2537
try:
2538
ray_index = cone.ambient_ray_indices().index(i)
2539
phi.append(R.gen(ray_index))
2540
point_preimage.append(point[i])
2541
except ValueError:
2542
phi.append(point[i])
2543
pullback_polys = [f(phi) for f in self.defining_polynomials()]
2544
patch = patch_cover.subscheme(pullback_polys)
2545
2546
patch._embedding_center = patch(point_preimage)
2547
patch._embedding_morphism = patch.hom(phi,self)
2548
return patch
2549
2550
def dimension(self):
2551
"""
2552
Return the dimension of ``self``.
2553
2554
OUTPUT:
2555
2556
Integer. If ``self`` is empty, `-1` is returned.
2557
2558
EXAMPLES::
2559
2560
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2561
sage: P1xP1 = ToricVariety(fan)
2562
sage: P1xP1.inject_variables()
2563
Defining z0, z1, z2, z3
2564
sage: P1 = P1xP1.subscheme(z0-z2)
2565
sage: P1.dimension()
2566
1
2567
sage: P1xP1.subscheme([z0-z2, (z0-z2)^2]).dimension()
2568
1
2569
sage: P1xP1.subscheme([z0,z2]).dimension()
2570
-1
2571
"""
2572
if '_dimension' in self.__dict__:
2573
return self._dimension
2574
npatches = self.ambient_space().fan().ngenerating_cones()
2575
dims = [ self.affine_patch(i).dimension() for i in range(0,npatches) ]
2576
self._dimension = max(dims)
2577
return self._dimension
2578
2579
def is_smooth(self, point=None):
2580
r"""
2581
Test whether the algebraic subscheme is smooth.
2582
2583
INPUT:
2584
2585
- ``point`` -- A point or ``None`` (default). The point to
2586
test smoothness at.
2587
2588
OUTPUT:
2589
2590
Boolean. If no point was specified, returns whether the
2591
algebraic subscheme is smooth everywhere. Otherwise,
2592
smoothness at the specified point is tested.
2593
2594
EXAMPLES::
2595
2596
sage: P2.<x,y,z> = toric_varieties.P2()
2597
sage: cuspidal_curve = P2.subscheme([y^2*z-x^3])
2598
sage: cuspidal_curve
2599
Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by:
2600
-x^3 + y^2*z
2601
sage: cuspidal_curve.is_smooth([1,1,1])
2602
True
2603
sage: cuspidal_curve.is_smooth([0,0,1])
2604
False
2605
sage: cuspidal_curve.is_smooth()
2606
False
2607
2608
Any sufficiently generic cubic hypersurface is smooth::
2609
2610
sage: P2.subscheme([y^2*z-x^3+z^3+1/10*x*y*z]).is_smooth()
2611
True
2612
2613
A more complicated example::
2614
2615
sage: dP6.<x0,x1,x2,x3,x4,x5> = toric_varieties.dP6()
2616
sage: disjointP1s = dP6.subscheme(x0*x3)
2617
sage: disjointP1s.is_smooth()
2618
True
2619
sage: intersectingP1s = dP6.subscheme(x0*x1)
2620
sage: intersectingP1s.is_smooth()
2621
False
2622
2623
A smooth hypersurface in a compact singular toric variety::
2624
2625
sage: lp = LatticePolytope(matrix([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)]).transpose())
2626
sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp)
2627
sage: Y = X.subscheme(x*v+y*u+t)
2628
sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)])
2629
sage: Y.is_smooth()
2630
True
2631
"""
2632
if not point is None:
2633
toric_patch = self.neighborhood(point)
2634
return toric_patch.is_smooth(toric_patch.embedding_center())
2635
2636
# testing smoothness everywhere tends to be expensive
2637
if '_smooth' in self.__dict__:
2638
return self._smooth
2639
npatches = self.ambient_space().fan().ngenerating_cones()
2640
self._smooth = all(self.affine_patch(i).is_smooth() for i in range(0,npatches))
2641
return self._smooth
2642
2643
2644
class AlgebraicScheme_subscheme_affine_toric(AlgebraicScheme_subscheme_toric):
2645
r"""
2646
Construct an algebraic subscheme of an affine toric variety.
2647
2648
.. WARNING::
2649
2650
You should not create objects of this class directly. The preferred
2651
method to construct such subschemes is to use
2652
:meth:`~ToricVariety_field.subscheme` method of
2653
:class:`toric varieties <ToricVariety_field>`.
2654
2655
INPUT:
2656
2657
- ``toric_variety`` -- ambient :class:`affine toric variety
2658
<ToricVariety_field>`;
2659
2660
- ``polynomials`` -- single polynomial, list, or ideal of defining
2661
polynomials in the coordinate ring of ``toric_variety``.
2662
2663
OUTPUT:
2664
2665
A :class:`algebraic subscheme of an affine toric variety
2666
<AlgebraicScheme_subscheme_affine_toric>`.
2667
2668
TESTS::
2669
2670
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2671
sage: P1xP1 = ToricVariety(fan, "x s y t")
2672
sage: P1xP1.inject_variables()
2673
Defining x, s, y, t
2674
sage: import sage.schemes.generic.algebraic_scheme as SCM
2675
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2676
... P1xP1, [x*s + y*t, x^3+y^3])
2677
sage: X
2678
Closed subscheme of 2-d toric variety
2679
covered by 4 affine patches defined by:
2680
x*s + y*t,
2681
x^3 + y^3
2682
2683
A better way to construct the same scheme as above::
2684
2685
sage: P1xP1.subscheme([x*s + y*t, x^3+y^3])
2686
Closed subscheme of 2-d toric variety
2687
covered by 4 affine patches defined by:
2688
x*s + y*t,
2689
x^3 + y^3
2690
"""
2691
2692
def __init__(self, toric_variety, polynomials):
2693
r"""
2694
See :class:`AlgebraicScheme_subscheme_toric` for documentation.
2695
2696
TESTS::
2697
2698
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2699
sage: P1xP1 = ToricVariety(fan, "x s y t")
2700
sage: P1xP1.inject_variables()
2701
Defining x, s, y, t
2702
sage: import sage.schemes.generic.algebraic_scheme as SCM
2703
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2704
... P1xP1, [x*s + y*t, x^3+y^3])
2705
sage: X
2706
Closed subscheme of 2-d toric variety
2707
covered by 4 affine patches defined by:
2708
x*s + y*t,
2709
x^3 + y^3
2710
"""
2711
assert toric_variety.is_affine(), 'The toric variety must be affine!'
2712
# Just to make sure that keyword arguments will be passed correctly
2713
super(AlgebraicScheme_subscheme_affine_toric, self).__init__(toric_variety,
2714
polynomials)
2715
2716
def dimension(self):
2717
"""
2718
Return the dimension of ``self``.
2719
2720
OUTPUT:
2721
2722
- integer.
2723
2724
EXAMPLES::
2725
2726
sage: P1xP1.<s0,s1,t0,t1> = toric_varieties.P1xP1()
2727
sage: P1 = P1xP1.subscheme(s0-s1)
2728
sage: P1.dimension()
2729
1
2730
2731
A more complicated example where the ambient toric variety is
2732
not smooth::
2733
2734
sage: X.<x,y> = toric_varieties.A2_Z2()
2735
sage: X.is_smooth()
2736
False
2737
sage: Y = X.subscheme([x*y, x^2])
2738
sage: Y
2739
Closed subscheme of 2-d affine toric variety defined by:
2740
x*y,
2741
x^2
2742
sage: Y.dimension()
2743
1
2744
"""
2745
if '_dimension' in self.__dict__:
2746
return self._dimension
2747
2748
if self.ambient_space().is_smooth():
2749
self._dimension = self.defining_ideal().dimension()
2750
else:
2751
self._dimension = self.affine_algebraic_patch().dimension()
2752
return self._dimension
2753
2754
def is_smooth(self, point=None):
2755
r"""
2756
Test whether the algebraic subscheme is smooth.
2757
2758
INPUT:
2759
2760
- ``point`` -- A point or ``None`` (default). The point to
2761
test smoothness at.
2762
2763
OUTPUT:
2764
2765
Boolean. If no point was specified, returns whether the
2766
algebraic subscheme is smooth everywhere. Otherwise,
2767
smoothness at the specified point is tested.
2768
2769
EXAMPLES::
2770
2771
sage: A2.<x,y> = toric_varieties.A2()
2772
sage: cuspidal_curve = A2.subscheme([y^2-x^3])
2773
sage: cuspidal_curve
2774
Closed subscheme of 2-d affine toric variety defined by:
2775
-x^3 + y^2
2776
sage: cuspidal_curve.is_smooth([1,1])
2777
True
2778
sage: cuspidal_curve.is_smooth([0,0])
2779
False
2780
sage: cuspidal_curve.is_smooth()
2781
False
2782
sage: circle = A2.subscheme(x^2+y^2-1)
2783
sage: circle.is_smooth([1,0])
2784
True
2785
sage: circle.is_smooth()
2786
True
2787
2788
A more complicated example where the ambient toric variety is
2789
not smooth::
2790
2791
sage: X.<x,y> = toric_varieties.A2_Z2() # 2-d affine space mod Z/2
2792
sage: X.is_smooth()
2793
False
2794
sage: Y = X.subscheme([x*y, x^2]) # (twice the x=0 curve) mod Z/2
2795
sage: Y
2796
Closed subscheme of 2-d affine toric variety defined by:
2797
x*y,
2798
x^2
2799
sage: Y.dimension() # Y is a Weil divisor but not Cartier
2800
1
2801
sage: Y.is_smooth()
2802
True
2803
sage: Y.is_smooth([0,0])
2804
True
2805
"""
2806
if not point is None:
2807
self._check_satisfies_equations(point)
2808
if self.ambient_space().is_smooth():
2809
R = self.ambient_space().coordinate_ring()
2810
point_subs = dict(zip(R.gens(), point))
2811
Jac = self.Jacobian().subs(point_subs)
2812
return not Jac.is_zero()
2813
else:
2814
self._embedding_center = self.point(point)
2815
affine = self.affine_algebraic_patch()
2816
return affine.is_smooth(affine.embedding_center())
2817
2818
# testing smoothness everywhere tends to be expensive
2819
if '_smooth' in self.__dict__:
2820
return self._smooth
2821
2822
if self.ambient_space().is_smooth():
2823
sing_dim = self.Jacobian().dimension()
2824
self._smooth = (sing_dim == -1)
2825
else:
2826
self._smooth = self.affine_algebraic_patch().is_smooth()
2827
2828
return self._smooth
2829
2830
2831
2832
2833