Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/generic/algebraic_scheme.py
4096 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.generic.affine_space.AffineSpace_generic>`),
9
10
* Projective spaces (:class:`ProjectiveSpace
11
<sage.schemes.generic.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 (
135
is_Ideal,
136
is_MPolynomialRing,
137
is_FiniteField,
138
is_RationalField,
139
ZZ)
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
import ambient_space
146
import affine_space
147
import projective_space
148
import morphism
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 coordiante 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
return self.__A._homset(*args, **kwds)
550
551
def _point_homset(self, *args, **kwds):
552
return self.__A._point_homset(*args, **kwds)
553
554
def _point(self, *args, **kwds):
555
return self.__A._point(*args, **kwds)
556
557
558
559
#*******************************************************************
560
class AlgebraicScheme_quasi(AlgebraicScheme):
561
"""
562
The quasi-affine or quasi-projective scheme `X - Y`, where `X` and `Y`
563
are both closed subschemes of a common ambient affine or projective
564
space.
565
566
.. WARNING::
567
568
You should not create objects of this class directly. The
569
preferred method to construct such subschemes is to use
570
:meth:`complement` method of algebraic schemes.
571
572
OUTPUT:
573
574
An instance of :class:`AlgebraicScheme_quasi`.
575
576
EXAMPLES::
577
578
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
579
sage: S = P.subscheme([])
580
sage: T = P.subscheme([x-y])
581
sage: T.complement(S)
582
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over
583
Integer Ring, where X is defined by:
584
(no polynomials)
585
and Y is defined by:
586
x - y
587
"""
588
589
def __init__(self, X, Y):
590
"""
591
The constructor.
592
593
INPUT:
594
595
- ``X``, ``Y`` -- two subschemes of the same ambient space.
596
597
TESTS::
598
599
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
600
sage: S = P.subscheme([])
601
sage: T = P.subscheme([x-y])
602
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
603
sage: AlgebraicScheme_quasi(S, T)
604
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:
605
(no polynomials)
606
and Y is defined by:
607
x - y
608
"""
609
self.__X = X
610
self.__Y = Y
611
if not isinstance(X, AlgebraicScheme_subscheme):
612
raise TypeError, "X must be a closed subscheme of an ambient space."
613
if not isinstance(Y, AlgebraicScheme_subscheme):
614
raise TypeError, "Y must be a closed subscheme of an ambient space."
615
if X.ambient_space() != Y.ambient_space():
616
raise ValueError, "X and Y must be embedded in the same ambient space."
617
# _latex_ and _repr_ assume all of the above conditions and should be
618
# probably changed if they are relaxed!
619
A = X.ambient_space()
620
self._base_ring = A.base_ring()
621
AlgebraicScheme.__init__(self, A)
622
623
def _latex_(self):
624
"""
625
Return a LaTeX representation of this algebraic scheme.
626
627
EXAMPLES::
628
629
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
630
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
631
sage: S = P.subscheme([])
632
sage: T = P.subscheme([x-y])
633
sage: U = AlgebraicScheme_quasi(S, T); U
634
Quasi-projective subscheme X - Y of Projective Space of dimension 2
635
over Integer Ring, where X is defined by:
636
(no polynomials)
637
and Y is defined by:
638
x - y
639
sage: U._latex_()
640
'\\text{Quasi-projective subscheme }
641
(X\\setminus Y)\\subset {\\mathbf P}_{\\Bold{Z}}^2,\\text{ where }
642
X \\text{ is defined by }\\text{no polynomials},\\text{ and }
643
Y \\text{ is defined by } x - y.'
644
"""
645
if affine_space.is_AffineSpace(self.ambient_space()):
646
t = "affine"
647
else:
648
t = "projective"
649
X = ', '.join(latex(f) for f in self.__X.defining_polynomials())
650
if not X:
651
X = r"\text{no polynomials}"
652
Y = ', '.join(latex(f) for f in self.__Y.defining_polynomials())
653
if not Y:
654
Y = r"\text{no polynomials}"
655
return (r"\text{Quasi-%s subscheme } (X\setminus Y)\subset %s,"
656
r"\text{ where } X \text{ is defined by }%s,"
657
r"\text{ and } Y \text{ is defined by } %s."
658
% (t, latex(self.ambient_space()), X, Y))
659
660
def _repr_(self):
661
"""
662
Return a string representation of this algebraic scheme.
663
664
EXAMPLES::
665
666
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
667
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
668
sage: S = P.subscheme([])
669
sage: T = P.subscheme([x-y])
670
sage: U = AlgebraicScheme_quasi(S, T); U
671
Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:
672
(no polynomials)
673
and Y is defined by:
674
x - y
675
sage: U._repr_()
676
'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'
677
"""
678
if affine_space.is_AffineSpace(self.ambient_space()):
679
t = "affine"
680
else:
681
t = "projective"
682
return ("Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\n"
683
"and Y is defined by:\n%s"
684
% (t, self.ambient_space(), str(self.__X).split("\n", 1)[1],
685
str(self.__Y).split("\n", 1)[1]))
686
687
def X(self):
688
"""
689
Return the scheme `X` such that self is represented as `X - Y`.
690
691
EXAMPLES::
692
693
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
694
sage: S = P.subscheme([])
695
sage: T = P.subscheme([x-y])
696
sage: U = T.complement(S)
697
sage: U.X() is S
698
True
699
"""
700
return self.__X
701
702
def Y(self):
703
"""
704
Return the scheme `Y` such that self is represented as `X - Y`.
705
706
EXAMPLES::
707
708
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
709
sage: S = P.subscheme([])
710
sage: T = P.subscheme([x-y])
711
sage: U = T.complement(S)
712
sage: U.Y() is T
713
True
714
"""
715
return self.__Y
716
717
def _check_satisfies_equations(self, v):
718
"""
719
Verify that the coordinates of v define a point on this scheme, or
720
raise a TypeError.
721
722
EXAMPLES::
723
724
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
725
sage: S = P.subscheme([])
726
sage: T = P.subscheme([x-y])
727
sage: U = T.complement(S)
728
sage: U._check_satisfies_equations([1, 2, 0])
729
True
730
sage: U._check_satisfies_equations([1, 1, 0])
731
Traceback (most recent call last):
732
...
733
TypeError: Coordinates [1, 1, 0] do not define a point on
734
Quasi-projective subscheme X - Y of Projective Space of dimension 2
735
over Integer Ring, where X is defined by:
736
(no polynomials)
737
and Y is defined by:
738
x - y
739
740
sage: U._check_satisfies_equations([1, 4])
741
Traceback (most recent call last):
742
...
743
TypeError: number of arguments does not match number of variables in parent
744
745
sage: A.<x, y> = AffineSpace(2, GF(7))
746
sage: S = A.subscheme([x^2-y])
747
sage: T = A.subscheme([x-y])
748
sage: U = T.complement(S)
749
sage: U._check_satisfies_equations([2, 4])
750
True
751
sage: U.point([2,4])
752
(2, 4)
753
sage: U._check_satisfies_equations(_)
754
True
755
sage: U._check_satisfies_equations([1, 1])
756
Traceback (most recent call last):
757
...
758
TypeError: Coordinates [1, 1] do not define a point on Quasi-affine
759
subscheme X - Y of Affine Space of dimension 2 over Finite
760
Field of size 7, where X is defined by:
761
x^2 - y
762
and Y is defined by:
763
x - y
764
sage: U._check_satisfies_equations([1, 0])
765
Traceback (most recent call last):
766
...
767
TypeError: Coordinates [1, 0] do not define a point on Quasi-affine
768
subscheme X - Y of Affine Space of dimension 2 over Finite
769
Field of size 7, where X is defined by:
770
x^2 - y
771
and Y is defined by:
772
x - y
773
774
TESTS:
775
776
The bug reported at #12211 has been fixed::
777
778
sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ)
779
sage: S = P.subscheme([x])
780
sage: T = P.subscheme([y, z])
781
sage: U = T.complement(S)
782
sage: U._check_satisfies_equations([0, 0, 1, 1])
783
True
784
"""
785
coords = list(v)
786
for f in self.__X.defining_polynomials():
787
if f(coords) != 0:
788
raise TypeError, "Coordinates %s do not define a point on %s"%(v,self)
789
for f in self.__Y.defining_polynomials():
790
if f(coords) != 0:
791
return True
792
raise TypeError, "Coordinates %s do not define a point on %s"%(v,self)
793
794
def rational_points(self, F=None, bound=0):
795
"""
796
Return the set of rational points on this algebraic scheme
797
over the field `F`.
798
799
EXAMPLES::
800
801
sage: A.<x, y> = AffineSpace(2, GF(7))
802
sage: S = A.subscheme([x^2-y])
803
sage: T = A.subscheme([x-y])
804
sage: U = T.complement(S)
805
sage: U.rational_points()
806
[(2, 4), (3, 2), (4, 2), (5, 4), (6, 1)]
807
sage: U.rational_points(GF(7^2, 'b'))
808
[(2, 4), (3, 2), (4, 2), (5, 4), (6, 1), (b, b + 4), (b + 1, 3*b + 5), (b + 2, 5*b + 1),
809
(b + 3, 6), (b + 4, 2*b + 6), (b + 5, 4*b + 1), (b + 6, 6*b + 5), (2*b, 4*b + 2),
810
(2*b + 1, b + 3), (2*b + 2, 5*b + 6), (2*b + 3, 2*b + 4), (2*b + 4, 6*b + 4),
811
(2*b + 5, 3*b + 6), (2*b + 6, 3), (3*b, 2*b + 1), (3*b + 1, b + 2), (3*b + 2, 5),
812
(3*b + 3, 6*b + 3), (3*b + 4, 5*b + 3), (3*b + 5, 4*b + 5), (3*b + 6, 3*b + 2),
813
(4*b, 2*b + 1), (4*b + 1, 3*b + 2), (4*b + 2, 4*b + 5), (4*b + 3, 5*b + 3),
814
(4*b + 4, 6*b + 3), (4*b + 5, 5), (4*b + 6, b + 2), (5*b, 4*b + 2), (5*b + 1, 3),
815
(5*b + 2, 3*b + 6), (5*b + 3, 6*b + 4), (5*b + 4, 2*b + 4), (5*b + 5, 5*b + 6),
816
(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),
817
(6*b + 4, 6), (6*b + 5, 5*b + 1), (6*b + 6, 3*b + 5)]
818
"""
819
if F is None:
820
F = self.base_ring()
821
822
if bound == 0:
823
if is_RationalField(F):
824
raise TypeError, "A positive bound (= %s) must be specified."%bound
825
if not is_FiniteField(F):
826
raise TypeError, "Argument F (= %s) must be a finite field."%F
827
pts = []
828
for P in self.ambient_space().rational_points(F):
829
try:
830
if self._check_satisfies_equations(list(P)):
831
pts.append(P)
832
except TypeError:
833
pass
834
pts.sort()
835
return pts
836
837
838
839
#*******************************************************************
840
class AlgebraicScheme_subscheme(AlgebraicScheme):
841
"""
842
An algebraic scheme presented as a closed subscheme is defined by
843
explicit polynomial equations. This is as opposed to a general
844
scheme, which could, e.g., be the Neron model of some object, and
845
for which we do not want to give explicit equations.
846
847
INPUT:
848
849
- ``A`` - ambient space (e.g. affine or projective `n`-space)
850
851
- ``polynomials`` - single polynomial, ideal or iterable of defining
852
polynomials; in any case polynomials must belong to the coordinate
853
ring of the ambient space and define valid polynomial functions (e.g.
854
they should be homogeneous in the case of a projective space)
855
856
OUTPUT:
857
858
- algebraic scheme
859
860
EXAMPLES::
861
862
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
863
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
864
sage: P.subscheme([x^2-y*z])
865
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
866
x^2 - y*z
867
sage: AlgebraicScheme_subscheme(P, [x^2-y*z])
868
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
869
x^2 - y*z
870
"""
871
872
def __init__(self, A, polynomials):
873
"""
874
See ``AlgebraicScheme_subscheme`` for documentation.
875
876
TESTS::
877
878
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
879
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
880
sage: P.subscheme([x^2-y*z])
881
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
882
x^2 - y*z
883
sage: AlgebraicScheme_subscheme(P, [x^2-y*z])
884
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
885
x^2 - y*z
886
"""
887
from sage.rings.polynomial.multi_polynomial_sequence import is_PolynomialSequence
888
889
AlgebraicScheme.__init__(self, A)
890
self._base_ring = A.base_ring()
891
R = A.coordinate_ring()
892
if is_Ideal(polynomials):
893
I = polynomials
894
polynomials = I.gens()
895
if I.ring() is R: # Otherwise we will recompute I later after
896
self.__I = I # converting generators to the correct ring
897
if isinstance(polynomials, tuple) or is_PolynomialSequence(polynomials) or is_iterator(polynomials):
898
polynomials = list(polynomials)
899
elif not isinstance(polynomials, list):
900
# Looks like we got a single polynomial
901
polynomials = [polynomials]
902
for n, f in enumerate(polynomials):
903
try:
904
polynomials[n] = R(f)
905
except TypeError:
906
raise TypeError("%s cannot be converted to a polynomial in "
907
"the coordinate ring of this %s!" % (f, A))
908
polynomials = tuple(polynomials)
909
self.__polys = A._validate(polynomials)
910
911
def _check_satisfies_equations(self, v):
912
"""
913
Verify that the coordinates of v define a point on this scheme, or
914
raise a TypeError.
915
916
EXAMPLES::
917
918
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
919
sage: S = P.subscheme([x^2-y*z])
920
sage: S._check_satisfies_equations([1, 1, 1])
921
True
922
sage: S._check_satisfies_equations([1, 0, 1])
923
Traceback (most recent call last):
924
...
925
TypeError: Coordinates [1, 0, 1] do not define a point on Closed subscheme
926
of Projective Space of dimension 2 over Rational Field defined by:
927
x^2 - y*z
928
sage: S._check_satisfies_equations([0, 0, 0])
929
Traceback (most recent call last):
930
...
931
TypeError: Coordinates [0, 0, 0] do not define a point on Closed subscheme
932
of Projective Space of dimension 2 over Rational Field defined by:
933
x^2 - y*z
934
"""
935
coords = list(v)
936
for f in self.defining_polynomials():
937
if f(coords) != 0: # it must be "!=0" instead of "if f(v)", e.g.,
938
# because of p-adic base rings.
939
raise TypeError, "Coordinates %s do not define a point on %s"%(coords,self)
940
try:
941
return self.ambient_space()._check_satisfies_equations(coords)
942
except TypeError:
943
raise TypeError, "Coordinates %s do not define a point on %s"%(coords,self)
944
945
def base_extend(self, R):
946
"""
947
Return the base change to the ring `R` of this scheme.
948
949
EXAMPLES::
950
951
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
952
sage: S = P.subscheme([x^2-y*z])
953
sage: S.base_extend(GF(11^2, 'b'))
954
Closed subscheme of Projective Space of dimension 2 over Finite Field in b of size 11^2 defined by:
955
x^2 - y*z
956
sage: S.base_extend(ZZ)
957
Traceback (most recent call last):
958
...
959
ValueError: no natural map from the base ring (=Finite Field of size 11) to R (=Integer Ring)!
960
"""
961
A = self.ambient_space().base_extend(R)
962
return A.subscheme(self.__polys)
963
964
def __cmp__(self, other):
965
"""
966
EXAMPLES::
967
968
sage: A.<x, y, z> = AffineSpace(3, QQ)
969
sage: X = A.subscheme([x*y, z])
970
sage: X == A.subscheme([z, x*y])
971
True
972
sage: X == A.subscheme([x*y, z^2])
973
False
974
sage: B.<u, v, t> = AffineSpace(3, QQ)
975
sage: X == B.subscheme([u*v, t])
976
False
977
"""
978
if not isinstance(other, AlgebraicScheme_subscheme):
979
return -1
980
A = self.ambient_space()
981
if other.ambient_space() != A:
982
return -1
983
return cmp(self.defining_ideal(), other.defining_ideal())
984
985
def _latex_(self):
986
"""
987
Return a LaTeX representation of this scheme.
988
989
EXAMPLES::
990
991
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
992
sage: S = P.subscheme([x^2-y*z])
993
sage: S
994
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
995
x^2 - y*z
996
sage: S._latex_()
997
'\\text{Closed subscheme of } {\\mathbf P}_{\\Bold{F}_{11}}^2 \\text{ defined by } x^{2} - y z'
998
sage: S = P.subscheme([x^2-y*z, x^5])
999
sage: S
1000
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1001
x^2 - y*z,
1002
x^5
1003
sage: S._latex_()
1004
'\\text{Closed subscheme of } {\\mathbf P}_{\\Bold{F}_{11}}^2 \\text{ defined by } x^{2} - y z, x^{5}'
1005
"""
1006
polynomials = ', '.join(latex(f) for f in self.defining_polynomials())
1007
if not polynomials:
1008
polynomials = r"\text{no polynomials}"
1009
return (r"\text{Closed subscheme of } %s \text{ defined by } %s"
1010
% (latex(self.ambient_space()), polynomials))
1011
1012
def _repr_(self):
1013
"""
1014
Return a string representation of this scheme.
1015
1016
EXAMPLES::
1017
1018
sage: P.<x, y, z> = ProjectiveSpace(2, GF(11))
1019
sage: S = P.subscheme([x^2-y*z])
1020
sage: S
1021
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1022
x^2 - y*z
1023
sage: S._repr_()
1024
'Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:\n x^2 - y*z'
1025
sage: S = P.subscheme([x^2-y*z, x^5])
1026
sage: S
1027
Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:
1028
x^2 - y*z,
1029
x^5
1030
sage: S._repr_()
1031
'Closed subscheme of Projective Space of dimension 2 over Finite Field of size 11 defined by:\n x^2 - y*z,\n x^5'
1032
"""
1033
polynomials = ',\n '.join(str(f) for f in self.defining_polynomials())
1034
if not polynomials:
1035
polynomials = '(no polynomials)'
1036
return ("Closed subscheme of %s defined by:\n %s"
1037
% (self.ambient_space(), polynomials))
1038
1039
def defining_polynomials(self):
1040
"""
1041
Return the polynomials that define this scheme as a subscheme
1042
of its ambient space.
1043
1044
OUTPUT:
1045
1046
A tuple of polynomials in the coordinate ring of the ambient
1047
space.
1048
1049
EXAMPLES::
1050
1051
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
1052
sage: S = P.subscheme([x^2-y*z, x^3+z^3])
1053
sage: S.defining_polynomials()
1054
(x^2 - y*z, x^3 + z^3)
1055
"""
1056
return self.__polys
1057
1058
def defining_ideal(self):
1059
"""
1060
Return the ideal that defines this scheme as a subscheme
1061
of its ambient space.
1062
1063
OUTPUT:
1064
1065
An ideal in the coordinate ring of the ambient space.
1066
1067
EXAMPLES::
1068
1069
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
1070
sage: S = P.subscheme([x^2-y*z, x^3+z^3])
1071
sage: S.defining_ideal()
1072
Ideal (x^2 - y*z, x^3 + z^3) of Multivariate Polynomial Ring in x, y, z over Integer Ring
1073
"""
1074
try:
1075
return self.__I
1076
except AttributeError:
1077
R = self.ambient_space().coordinate_ring()
1078
self.__I = R.ideal(self.defining_polynomials())
1079
return self.__I
1080
1081
# Note: dimension must be implemented by the derived classes
1082
def codimension(self):
1083
r"""
1084
Return the codimension of the algebraic subscheme.
1085
1086
OUTPUT:
1087
1088
Integer.
1089
1090
EXAMPLES::
1091
1092
sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ)
1093
sage: V = PP.subscheme(x*y)
1094
sage: V.codimension()
1095
1
1096
sage: V.dimension()
1097
3
1098
"""
1099
return self.ambient_space().dimension() - self.dimension()
1100
1101
def irreducible_components(self):
1102
r"""
1103
Return the irreducible components of this algebraic scheme, as
1104
subschemes of the same ambient space.
1105
1106
OUTPUT: an immutable sequence of irreducible subschemes of the
1107
ambient space of this scheme
1108
1109
The components are cached.
1110
1111
EXAMPLES:
1112
1113
We define what is clearly a union of four hypersurfaces in
1114
`\P^4_{\QQ}` then find the irreducible components::
1115
1116
sage: PP.<x,y,z,w,v> = ProjectiveSpace(4,QQ)
1117
sage: V = PP.subscheme( (x^2 - y^2 - z^2)*(w^5 - 2*v^2*z^3)* w * (v^3 - x^2*z) )
1118
sage: V.irreducible_components()
1119
[
1120
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1121
w,
1122
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1123
x^2 - y^2 - z^2,
1124
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1125
x^2*z - v^3,
1126
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1127
w^5 - 2*z^3*v^2
1128
]
1129
1130
We verify that the irrelevant ideal isn't accidently returned
1131
(see trac 6920)::
1132
1133
sage: PP.<x,y,z,w> = ProjectiveSpace(3,QQ)
1134
sage: f = x^3 + y^3 + z^3 + w^3
1135
sage: R = f.parent()
1136
sage: I = [f] + [f.derivative(zz) for zz in PP.gens()]
1137
sage: V = PP.subscheme(I)
1138
sage: V.irreducible_components()
1139
[
1140
<BLANKLINE>
1141
]
1142
1143
The same polynomial as above defines a scheme with a
1144
nontrivial irreducible component in affine space (instead of
1145
the empty scheme as above)::
1146
1147
sage: AA.<x,y,z,w> = AffineSpace(4,QQ)
1148
sage: V = AA.subscheme(I)
1149
sage: V.irreducible_components()
1150
[
1151
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
1152
w,
1153
z,
1154
y,
1155
x
1156
]
1157
"""
1158
try:
1159
return self.__irreducible_components
1160
except AttributeError:
1161
pass
1162
I = self.defining_ideal()
1163
P = I.associated_primes()
1164
if self.is_projective():
1165
# In the projective case, we must exclude the prime ideals
1166
# that contain the irrelevant ideal, which is the ideal
1167
# generated by the variables, which are the gens of the
1168
# base ring.
1169
G = I.ring().gens()
1170
# We make a list of ideals with the property that "any"
1171
# of the elements of G are not in the ideal.
1172
P = [J for J in P if any(g not in J for g in G)]
1173
1174
A = self.ambient_space()
1175
C = Sequence([A.subscheme(X) for X in P], check=False, cr=True)
1176
C.sort()
1177
C.set_immutable()
1178
self.__irreducible_components = C
1179
return C
1180
1181
def Jacobian_matrix(self):
1182
r"""
1183
Return the matrix `\frac{\partial f_i}{\partial x_j}` of
1184
(formal) partial derivatives.
1185
1186
OUTPUT:
1187
1188
A matrix of polynomials.
1189
1190
EXAMPLES::
1191
1192
sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ)
1193
sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2))
1194
sage: twisted_cubic.Jacobian_matrix()
1195
[ y -2*x w 0]
1196
[ z -y -x w]
1197
[ 0 z -2*y x]
1198
"""
1199
R = self.ambient_space().coordinate_ring()
1200
return jacobian(self.defining_polynomials(), R.gens())
1201
1202
def Jacobian(self):
1203
r"""
1204
Return the Jacobian ideal.
1205
1206
This is the ideal generated by
1207
1208
* the `d\times d` minors of the Jacobian matrix, where `d` is
1209
the :meth:`codimension` of the algebraic scheme, and
1210
1211
* the defining polynomials of the algebraic scheme. Note that
1212
some authors do not include these in the definition of the
1213
Jacobian ideal. An example of a reference that does include
1214
the defining equations is [LazarsfeldJacobian].
1215
1216
OUTPUT:
1217
1218
An ideal in the coordinate ring of the ambient space.
1219
1220
REFERENCES:
1221
1222
.. [LazarsfeldJacobian]
1223
Robert Lazarsfeld:
1224
Positivity in algebraic geometry II;
1225
Positivity for Vector Bundles, and Multiplier Ideals,
1226
page 181.
1227
1228
EXAMPLES::
1229
1230
sage: P3.<w,x,y,z> = ProjectiveSpace(3, QQ)
1231
sage: twisted_cubic = P3.subscheme(matrix([[w, x, y],[x, y, z]]).minors(2))
1232
sage: twisted_cubic.Jacobian()
1233
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,
1234
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,
1235
w*y) of Multivariate Polynomial Ring in w, x, y, z over Rational Field
1236
sage: twisted_cubic.defining_ideal()
1237
Ideal (-x^2 + w*y, -x*y + w*z, -y^2 + x*z) of Multivariate Polynomial Ring
1238
in w, x, y, z over Rational Field
1239
"""
1240
d = self.codimension()
1241
minors = self.Jacobian_matrix().minors(d)
1242
I = self.defining_ideal()
1243
minors = tuple([ I.reduce(m) for m in minors ])
1244
return I.ring().ideal(I.gens() + minors)
1245
1246
def reduce(self):
1247
r"""
1248
Return the corresponding reduced algebraic space associated to this
1249
scheme.
1250
1251
EXAMPLES: First we construct the union of a doubled and tripled
1252
line in the affine plane over `\QQ` ::
1253
1254
sage: A.<x,y> = AffineSpace(2, QQ)
1255
sage: X = A.subscheme([(x-1)^2*(x-y)^3]); X
1256
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1257
x^5 - 3*x^4*y + 3*x^3*y^2 - x^2*y^3 - 2*x^4 + 6*x^3*y
1258
- 6*x^2*y^2 + 2*x*y^3 + x^3 - 3*x^2*y + 3*x*y^2 - y^3
1259
sage: X.dimension()
1260
1
1261
1262
Then we compute the corresponding reduced scheme::
1263
1264
sage: Y = X.reduce(); Y
1265
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1266
x^2 - x*y - x + y
1267
1268
Finally, we verify that the reduced scheme `Y` is the union
1269
of those two lines::
1270
1271
sage: L1 = A.subscheme([x-1]); L1
1272
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1273
x - 1
1274
sage: L2 = A.subscheme([x-y]); L2
1275
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1276
x - y
1277
sage: W = L1.union(L2); W # taken in ambient space
1278
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1279
x^2 - x*y - x + y
1280
sage: Y == W
1281
True
1282
"""
1283
try:
1284
return self._reduce
1285
except AttributeError:
1286
r = self.defining_ideal().radical()
1287
A = self.ambient_space()
1288
V = A.subscheme(r)
1289
V._reduce = V # so knows it is already reduced!
1290
self._reduce = V
1291
return V
1292
1293
def union(self, other):
1294
"""
1295
Return the scheme-theoretic union of self and other in their common
1296
ambient space.
1297
1298
EXAMPLES: We construct the union of a line and a tripled-point on
1299
the line.
1300
1301
::
1302
1303
sage: A.<x,y> = AffineSpace(2, QQ)
1304
sage: I = ideal([x,y])^3
1305
sage: P = A.subscheme(I)
1306
sage: L = A.subscheme([y-1])
1307
sage: S = L.union(P); S
1308
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1309
y^4 - y^3,
1310
x*y^3 - x*y^2,
1311
x^2*y^2 - x^2*y,
1312
x^3*y - x^3
1313
sage: S.dimension()
1314
1
1315
sage: S.reduce()
1316
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1317
y^2 - y,
1318
x*y - x
1319
1320
We can also use the notation "+" for the union::
1321
1322
sage: A.subscheme([x]) + A.subscheme([y^2 - (x^3+1)])
1323
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1324
x^4 - x*y^2 + x
1325
1326
Saving and loading::
1327
1328
sage: loads(S.dumps()) == S
1329
True
1330
"""
1331
if not isinstance(other, AlgebraicScheme_subscheme):
1332
raise TypeError, "other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1333
A = self.ambient_space()
1334
if other.ambient_space() != A:
1335
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1336
return A.subscheme(self.defining_ideal().intersection(other.defining_ideal()))
1337
1338
__add__ = union
1339
1340
def intersection(self, other):
1341
"""
1342
Return the scheme-theoretic intersection of self and other in their
1343
common ambient space.
1344
1345
EXAMPLES::
1346
1347
sage: A.<x, y> = AffineSpace(2, ZZ)
1348
sage: X = A.subscheme([x^2-y])
1349
sage: Y = A.subscheme([y])
1350
sage: X.intersection(Y)
1351
Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by:
1352
x^2 - y,
1353
y
1354
"""
1355
if not isinstance(other, AlgebraicScheme_subscheme):
1356
raise TypeError, "other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1357
A = self.ambient_space()
1358
if other.ambient_space() != A:
1359
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1360
return A.subscheme(self.defining_ideal() + other.defining_ideal())
1361
1362
def complement(self, other=None):
1363
"""
1364
Return the scheme-theoretic complement other - self, where
1365
self and other are both closed algebraic subschemes of the
1366
same ambient space.
1367
1368
If other is unspecified, it is taken to be the ambient space
1369
of self.
1370
1371
EXAMPLES::
1372
1373
sage: A.<x, y, z> = AffineSpace(3, ZZ)
1374
sage: X = A.subscheme([x+y-z])
1375
sage: Y = A.subscheme([x-y+z])
1376
sage: Y.complement(X)
1377
Quasi-affine subscheme X - Y of Affine Space of
1378
dimension 3 over Integer Ring, where X is defined by:
1379
x + y - z
1380
and Y is defined by:
1381
x - y + z
1382
sage: Y.complement()
1383
Quasi-affine subscheme X - Y of Affine Space of
1384
dimension 3 over Integer Ring, where X is defined by:
1385
(no polynomials)
1386
and Y is defined by:
1387
x - y + z
1388
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
1389
sage: X = P.subscheme([x^2+y^2+z^2])
1390
sage: Y = P.subscheme([x*y+y*z+z*x])
1391
sage: Y.complement(X)
1392
Quasi-projective subscheme X - Y of Projective Space of
1393
dimension 2 over Rational Field, where X is defined by:
1394
x^2 + y^2 + z^2
1395
and Y is defined by:
1396
x*y + x*z + y*z
1397
sage: Y.complement(P)
1398
Quasi-projective subscheme X - Y of Projective Space of
1399
dimension 2 over Rational Field, where X is defined by:
1400
(no polynomials)
1401
and Y is defined by:
1402
x*y + x*z + y*z
1403
"""
1404
A = self.ambient_space()
1405
if other is None:
1406
other = A.subscheme([])
1407
elif not isinstance(other, AlgebraicScheme_subscheme):
1408
if other == A:
1409
other = A.subscheme([])
1410
else:
1411
raise TypeError, \
1412
"Argument other (=%s) must be a closed algebraic subscheme of an ambient space"%other
1413
if other.ambient_space() != A:
1414
raise ValueError, "other (=%s) must be in the same ambient space as self"%other
1415
return AlgebraicScheme_quasi(other, self)
1416
1417
def rational_points(self, F=None, bound=0):
1418
"""
1419
Return the rational points on the algebraic subscheme.
1420
1421
EXAMPLES:
1422
1423
One can enumerate points up to a given bound on a projective scheme
1424
over the rationals::
1425
1426
sage: E = EllipticCurve('37a')
1427
sage: E.rational_points(bound=8)
1428
[(-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)]
1429
1430
For a small finite field, the complete set of points can be
1431
enumerated. ::
1432
1433
sage: Etilde = E.base_extend(GF(3))
1434
sage: Etilde.rational_points()
1435
[(0 : 0 : 1), (0 : 1 : 0), (0 : 2 : 1), (1 : 0 : 1),
1436
(1 : 2 : 1), (2 : 0 : 1), (2 : 2 : 1)]
1437
1438
The class of hyperelliptic curves does not (yet) support
1439
desingularization of the places at infinity into two points::
1440
1441
sage: FF = FiniteField(7)
1442
sage: P.<x> = PolynomialRing(FiniteField(7))
1443
sage: C = HyperellipticCurve(x^8+x+1)
1444
sage: C.rational_points()
1445
[(0 : 1 : 0), (0 : 1 : 1), (0 : 6 : 1), (2 : 0 : 1),
1446
(4 : 0 : 1), (6 : 1 : 1), (6 : 6 : 1)]
1447
1448
TODO:
1449
1450
1. The above algorithms enumerate all projective points and
1451
test whether they lie on the scheme; Implement a more naive
1452
sieve at least for covers of the projective line.
1453
1454
2. Implement Stoll's model in weighted projective space to
1455
resolve singularities and find two points (1 : 1 : 0) and
1456
(-1 : 1 : 0) at infinity.
1457
"""
1458
if F == None:
1459
F = self.base_ring()
1460
X = self(F)
1461
if is_RationalField(F) or F == ZZ:
1462
if not bound > 0:
1463
raise TypeError, "A positive bound (= %s) must be specified."%bound
1464
try:
1465
return X.points(bound)
1466
except TypeError:
1467
raise TypeError, "Unable to enumerate points over %s."%F
1468
try:
1469
return X.points()
1470
except TypeError:
1471
raise TypeError, "Unable to enumerate points over %s."%F
1472
1473
1474
1475
#*******************************************************************
1476
# Affine varieties
1477
#*******************************************************************
1478
class AlgebraicScheme_subscheme_affine(AlgebraicScheme_subscheme):
1479
"""
1480
Construct an algebraic subscheme of affine space.
1481
1482
.. WARNING::
1483
1484
You should not create objects of this class directly. The
1485
preferred method to construct such subschemes is to use
1486
:meth:`~sage.schemes.generic.affine_space.AffineSpace_generic.subscheme`
1487
method of :class:`affine space
1488
<sage.schemes.generic.affine_space.AffineSpace_generic>`.
1489
1490
INPUT:
1491
1492
- ``A`` -- ambient :class:`affine space
1493
<sage.schemes.generic.affine_space.AffineSpace_generic>`
1494
1495
- ``polynomials`` -- single polynomial, ideal or iterable of
1496
defining polynomials.
1497
1498
EXAMPLES::
1499
1500
sage: A3.<x, y, z> = AffineSpace(3, QQ)
1501
sage: A3.subscheme([x^2-y*z])
1502
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
1503
x^2 - y*z
1504
1505
TESTS::
1506
1507
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme_affine
1508
sage: AlgebraicScheme_subscheme_affine(A3, [x^2-y*z])
1509
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
1510
x^2 - y*z
1511
"""
1512
1513
def _morphism(self, *args, **kwds):
1514
return morphism.SchemeMorphism_polynomial_affine_space(*args, **kwds)
1515
1516
def dimension(self):
1517
"""
1518
Return the dimension of the affine algebraic subscheme.
1519
1520
OUTPUT:
1521
1522
Integer.
1523
1524
EXAMPLES::
1525
1526
sage: A.<x,y> = AffineSpace(2, QQ)
1527
sage: A.subscheme([]).dimension()
1528
2
1529
sage: A.subscheme([x]).dimension()
1530
1
1531
sage: A.subscheme([x^5]).dimension()
1532
1
1533
sage: A.subscheme([x^2 + y^2 - 1]).dimension()
1534
1
1535
sage: A.subscheme([x*(x-1), y*(y-1)]).dimension()
1536
0
1537
1538
Something less obvious::
1539
1540
sage: A.<x,y,z,w> = AffineSpace(4, QQ)
1541
sage: X = A.subscheme([x^2, x^2*y^2 + z^2, z^2 - w^2, 10*x^2 + w^2 - z^2])
1542
sage: X
1543
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
1544
x^2,
1545
x^2*y^2 + z^2,
1546
z^2 - w^2,
1547
10*x^2 - z^2 + w^2
1548
sage: X.dimension()
1549
1
1550
"""
1551
try:
1552
return self.__dimension
1553
except AttributeError:
1554
self.__dimension = self.defining_ideal().dimension()
1555
return self.__dimension
1556
1557
def projective_embedding(self, i=None, X=None):
1558
"""
1559
Returns a morphism from this affine scheme into an ambient
1560
projective space of the same dimension.
1561
1562
INPUT:
1563
1564
- ``i`` -- integer (default: dimension of self = last
1565
coordinate) determines which projective embedding to compute. The
1566
embedding is that which has a 1 in the i-th coordinate, numbered
1567
from 0.
1568
1569
1570
- ``X`` -- (default: None) projective scheme, i.e., codomain of
1571
morphism; this is constructed if it is not given.
1572
1573
EXAMPLES::
1574
1575
sage: A.<x, y, z> = AffineSpace(3, ZZ)
1576
sage: S = A.subscheme([x*y-z])
1577
sage: S.projective_embedding()
1578
Scheme morphism:
1579
From: Closed subscheme of Affine Space of dimension 3 over Integer Ring defined by:
1580
x*y - z
1581
To: Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by:
1582
x0*x1 - x2*x3
1583
Defn: Defined on coordinates by sending (x, y, z) to
1584
(x : y : z : 1)
1585
"""
1586
AA = self.ambient_space()
1587
n = AA.dimension_relative()
1588
if i is None:
1589
try:
1590
i = self._default_embedding_index
1591
except AttributeError:
1592
i = int(n)
1593
else:
1594
i = int(i)
1595
if i < 0 or i > n:
1596
raise ValueError, \
1597
"Argument i (=%s) must be between 0 and %s, inclusive"%(i, n)
1598
try:
1599
return self.__projective_embedding[i]
1600
except AttributeError:
1601
self.__projective_embedding = {}
1602
except KeyError:
1603
pass
1604
if X is None:
1605
PP = projective_space.ProjectiveSpace(n, AA.base_ring())
1606
v = list(PP.gens())
1607
z = v.pop(i)
1608
v.append(z)
1609
polys = self.defining_polynomials()
1610
X = PP.subscheme([ f.homogenize()(v) for f in polys ])
1611
R = AA.coordinate_ring()
1612
v = list(R.gens())
1613
v.insert(i, R(1))
1614
phi = self.hom(v, X)
1615
self.__projective_embedding[i] = phi
1616
return phi
1617
1618
def is_smooth(self, point=None):
1619
r"""
1620
Test whether the algebraic subscheme is smooth.
1621
1622
INPUT:
1623
1624
- ``point`` -- A point or ``None`` (default). The point to
1625
test smoothness at.
1626
1627
OUTPUT:
1628
1629
Boolean. If no point was specified, returns whether the
1630
algebraic subscheme is smooth everywhere. Otherwise,
1631
smoothness at the specified point is tested.
1632
1633
EXAMPLES::
1634
1635
sage: A2.<x,y> = AffineSpace(2,QQ)
1636
sage: cuspidal_curve = A2.subscheme([y^2-x^3])
1637
sage: cuspidal_curve
1638
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1639
-x^3 + y^2
1640
sage: smooth_point = cuspidal_curve.point([1,1])
1641
sage: smooth_point in cuspidal_curve
1642
True
1643
sage: singular_point = cuspidal_curve.point([0,0])
1644
sage: singular_point in cuspidal_curve
1645
True
1646
sage: cuspidal_curve.is_smooth(smooth_point)
1647
True
1648
sage: cuspidal_curve.is_smooth(singular_point)
1649
False
1650
sage: cuspidal_curve.is_smooth()
1651
False
1652
"""
1653
R = self.ambient_space().coordinate_ring()
1654
if not point is None:
1655
self._check_satisfies_equations(point)
1656
point_subs = dict(zip(R.gens(), point))
1657
Jac = self.Jacobian().subs(point_subs)
1658
return not Jac.is_zero()
1659
1660
# testing smoothness everywhere tends to be expensive
1661
try:
1662
return self._smooth
1663
except AttributeError:
1664
pass
1665
sing_dim = self.Jacobian().dimension()
1666
self._smooth = (sing_dim == -1)
1667
return self._smooth
1668
1669
1670
1671
#*******************************************************************
1672
# Projective varieties
1673
#*******************************************************************
1674
class AlgebraicScheme_subscheme_projective(AlgebraicScheme_subscheme):
1675
"""
1676
Construct an algebraic subscheme of projective space.
1677
1678
.. WARNING::
1679
1680
You should not create objects of this class directly. The
1681
preferred method to construct such subschemes is to use
1682
:meth:`~sage.schemes.generic.projective_space.ProjectiveSpace_field.subscheme`
1683
method of :class:`projective space
1684
<sage.schemes.generic.projective_space.ProjectiveSpace_field>`.
1685
1686
INPUT:
1687
1688
- ``A`` -- ambient :class:`projective space
1689
<sage.schemes.generic.projective_space.ProjectiveSpace_field>`.
1690
1691
- ``polynomials`` -- single polynomial, ideal or iterable of
1692
defining homogeneous polynomials.
1693
1694
EXAMPLES::
1695
1696
sage: P.<x, y, z> = ProjectiveSpace(2, QQ)
1697
sage: P.subscheme([x^2-y*z])
1698
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1699
x^2 - y*z
1700
1701
TESTS::
1702
1703
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme_projective
1704
sage: AlgebraicScheme_subscheme_projective(P, [x^2-y*z])
1705
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1706
x^2 - y*z
1707
"""
1708
1709
def _morphism(self, *args, **kwds):
1710
r"""
1711
Construct a morphism determined by action on points of ``self``.
1712
1713
For internal use only.
1714
1715
INPUT:
1716
1717
- same as for
1718
:class:`~sage.schemes.generic.morphism.SchemeMorphism_polynomial_projective_space`.
1719
1720
OUPUT:
1721
1722
- :class:`~sage.schemes.generic.morphism.SchemeMorphism_polynomial_projective_space`.
1723
1724
TESTS::
1725
1726
sage: P1.<x,y> = ProjectiveSpace(1,QQ)
1727
sage: P2 = ProjectiveSpace(2,QQ)
1728
sage: H12 = P1.Hom(P2)
1729
sage: H12([x^2,x*y, y^2]) # indirect doctest
1730
Scheme morphism:
1731
From: Projective Space of dimension 1 over Rational Field
1732
To: Projective Space of dimension 2 over Rational Field
1733
Defn: Defined on coordinates by sending (x : y) to
1734
(x^2 : x*y : y^2)
1735
sage: P1._morphism(H12, [x^2,x*y, y^2])
1736
Scheme morphism:
1737
From: Projective Space of dimension 1 over Rational Field
1738
To: Projective Space of dimension 2 over Rational Field
1739
Defn: Defined on coordinates by sending (x : y) to
1740
(x^2 : x*y : y^2)
1741
"""
1742
return morphism.SchemeMorphism_polynomial_projective_space(*args, **kwds)
1743
1744
def dimension(self):
1745
"""
1746
Return the dimension of the projective algebraic subscheme.
1747
1748
OUTPUT:
1749
1750
Integer.
1751
1752
EXAMPLES::
1753
1754
sage: P2.<x,y,z> = ProjectiveSpace(2, QQ)
1755
sage: P2.subscheme([]).dimension()
1756
2
1757
sage: P2.subscheme([x]).dimension()
1758
1
1759
sage: P2.subscheme([x^5]).dimension()
1760
1
1761
sage: P2.subscheme([x^2 + y^2 - z^2]).dimension()
1762
1
1763
sage: P2.subscheme([x*(x-z), y*(y-z)]).dimension()
1764
0
1765
1766
Something less obvious::
1767
1768
sage: P3.<x,y,z,w,t> = ProjectiveSpace(4, QQ)
1769
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])
1770
sage: X
1771
Closed subscheme of Projective Space of dimension 4 over Rational Field defined by:
1772
x^2,
1773
x^2*y^2 + z^2*t^2,
1774
z^2 - w^2,
1775
10*x^2 - z^2 + w^2
1776
sage: X.dimension()
1777
1
1778
"""
1779
try:
1780
return self.__dimension
1781
except AttributeError:
1782
self.__dimension = self.defining_ideal().dimension() - 1
1783
return self.__dimension
1784
1785
def affine_patch(self, i):
1786
r"""
1787
Return the `i^{th}` affine patch of this projective scheme.
1788
This is the intersection with this `i^{th}` affine patch of
1789
its ambient space.
1790
1791
INPUT:
1792
1793
- ``i`` -- integer between 0 and dimension of self, inclusive.
1794
1795
OUTPUT:
1796
1797
An affine algebraic scheme with fixed
1798
:meth:`embedding_morphism` equal to the default
1799
:meth:`projective_embedding` map`.
1800
1801
EXAMPLES::
1802
1803
sage: PP = ProjectiveSpace(2, QQ, names='X,Y,Z')
1804
sage: X,Y,Z = PP.gens()
1805
sage: C = PP.subscheme(X^3*Y + Y^3*Z + Z^3*X)
1806
sage: U = C.affine_patch(0)
1807
sage: U
1808
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1809
x0^3*x1 + x1^3 + x0
1810
sage: U.embedding_morphism()
1811
Scheme morphism:
1812
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1813
x0^3*x1 + x1^3 + x0
1814
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1815
X^3*Y + Y^3*Z + X*Z^3
1816
Defn: Defined on coordinates by sending (x0, x1) to
1817
(1 : x0 : x1)
1818
sage: U.projective_embedding() is U.embedding_morphism()
1819
True
1820
"""
1821
i = int(i) # implicit type checking
1822
PP = self.ambient_space()
1823
n = PP.dimension()
1824
if i < 0 or i > n:
1825
raise ValueError, "Argument i (= %s) must be between 0 and %s."%(i, n)
1826
try:
1827
return self.__affine_patches[i]
1828
except AttributeError:
1829
self.__affine_patches = {}
1830
except KeyError:
1831
pass
1832
AA = PP.affine_patch(i)
1833
phi = AA.projective_embedding()
1834
polys = self.defining_polynomials()
1835
xi = phi.defining_polynomials()
1836
U = AA.subscheme([ f(xi) for f in polys ])
1837
U._default_embedding_index = i
1838
phi = U.projective_embedding(i, self)
1839
self.__affine_patches[i] = U
1840
U._embedding_morphism = phi
1841
return U
1842
1843
def _best_affine_patch(self, point):
1844
r"""
1845
Return the best affine patch of the ambient projective space.
1846
1847
The "best" affine patch is where you end up dividing by the
1848
homogeneous coordinate with the largest absolutue
1849
value. Division by small numbers is numerically unstable.
1850
1851
INPUT:
1852
1853
- ``point`` -- a point of the algebraic subscheme.
1854
1855
OUTPUT:
1856
1857
Integer. The index of the patch. See :meth:`affine_patch`.
1858
1859
EXAMPLES::
1860
1861
sage: P.<x,y,z>= ProjectiveSpace(QQ,2)
1862
sage: S = P.subscheme(x+2*y+3*z)
1863
sage: S._best_affine_patch(P.point([0,-3,2]))
1864
1
1865
sage: S._best_affine_patch([0,-3,2])
1866
1
1867
1868
TESTS::
1869
1870
sage: F = GF(3)
1871
sage: P.<x,y,z>= ProjectiveSpace(F,2)
1872
sage: S._best_affine_patch([0,1,2])
1873
2
1874
"""
1875
point = list(point)
1876
try:
1877
abs_point = map(abs, point)
1878
except ArithmeticError:
1879
# our base ring does not know abs
1880
abs_point = point
1881
# find best patch
1882
i_max = 0
1883
p_max = abs_point[i_max]
1884
for i in range(1,len(point)):
1885
if abs_point[i]>p_max:
1886
i_max = i
1887
p_max = abs_point[i_max]
1888
return i_max
1889
1890
def neighborhood(self, point):
1891
r"""
1892
Return an affine algebraic subscheme isomorphic to a
1893
neighborhood of the ``point``.
1894
1895
INPUT:
1896
1897
- ``point`` -- a point of the projective subscheme.
1898
1899
OUTPUT
1900
1901
An affine algebraic scheme (polynomial equations in affine
1902
space) ``result`` such that
1903
1904
* :meth:`embedding_morphism
1905
<AlgebraicScheme.embedding_morphism>` is an isomorphism to a
1906
neighborhood of ``point``
1907
1908
* :meth:`embedding_center <AlgebraicScheme.embedding_center>`
1909
is mapped to ``point``.
1910
1911
EXAMPLES::
1912
1913
sage: P.<x,y,z>= ProjectiveSpace(QQ,2)
1914
sage: S = P.subscheme(x+2*y+3*z)
1915
sage: s = S.point([0,-3,2]); s
1916
(0 : -3/2 : 1)
1917
sage: patch = S.neighborhood(s); patch
1918
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1919
x0 + 3*x1
1920
sage: patch.embedding_morphism()
1921
Scheme morphism:
1922
From: Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
1923
x0 + 3*x1
1924
To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1925
x + 2*y + 3*z
1926
Defn: Defined on coordinates by sending (x0, x1) to
1927
(-3*x1 : -3/2 : x1 + 1)
1928
sage: patch.embedding_center()
1929
(0, 0)
1930
sage: patch.embedding_morphism()([0,0])
1931
(0 : -3/2 : 1)
1932
sage: patch.embedding_morphism()(patch.embedding_center())
1933
(0 : -3/2 : 1)
1934
"""
1935
point = list(point)
1936
self._check_satisfies_equations(point)
1937
PP = self.ambient_space()
1938
n = PP.dimension()
1939
i = self._best_affine_patch(point)
1940
1941
patch_cover = PP.affine_patch(i)
1942
R = patch_cover.coordinate_ring()
1943
1944
phi = list(point)
1945
for j in range(0,i):
1946
phi[j] = phi[j] + R.gen(j)
1947
for j in range(i,n):
1948
phi[j+1] = phi[j+1] + R.gen(j)
1949
1950
pullback_polys = [f(phi) for f in self.defining_polynomials()]
1951
patch = patch_cover.subscheme(pullback_polys)
1952
patch_hom = patch.hom(phi,self)
1953
patch._embedding_center = patch.point([0]*n)
1954
patch._embedding_morphism = patch_hom
1955
return patch
1956
1957
def is_smooth(self, point=None):
1958
r"""
1959
Test whether the algebraic subscheme is smooth.
1960
1961
INPUT:
1962
1963
- ``point`` -- A point or ``None`` (default). The point to
1964
test smoothness at.
1965
1966
OUTPUT:
1967
1968
Boolean. If no point was specified, returns whether the
1969
algebraic subscheme is smooth everywhere. Otherwise,
1970
smoothness at the specified point is tested.
1971
1972
EXAMPLES::
1973
1974
sage: P2.<x,y,z> = ProjectiveSpace(2,QQ)
1975
sage: cuspidal_curve = P2.subscheme([y^2*z-x^3])
1976
sage: cuspidal_curve
1977
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
1978
-x^3 + y^2*z
1979
sage: cuspidal_curve.is_smooth([1,1,1])
1980
True
1981
sage: cuspidal_curve.is_smooth([0,0,1])
1982
False
1983
sage: cuspidal_curve.is_smooth()
1984
False
1985
sage: P2.subscheme([y^2*z-x^3+z^3+1/10*x*y*z]).is_smooth()
1986
True
1987
1988
TESTS::
1989
1990
sage: H = P2.subscheme(x)
1991
sage: H.is_smooth() # one of the few cases where the cone over the subvariety is smooth
1992
True
1993
"""
1994
if not point is None:
1995
self._check_satisfies_equations(point)
1996
R = self.ambient_space().coordinate_ring()
1997
point_subs = dict(zip(R.gens(), point))
1998
Jac = self.Jacobian().subs(point_subs)
1999
return not Jac.is_zero()
2000
2001
# testing smoothness everywhere tends to be expensive
2002
try:
2003
return self._smooth
2004
except AttributeError:
2005
pass
2006
sing_dim = self.Jacobian().dimension()
2007
# We really test the affine cone here; the origin is always a singular point:
2008
self._smooth = (sing_dim <= 0)
2009
return self._smooth
2010
2011
2012
#*******************************************************************
2013
# Toric varieties
2014
#*******************************************************************
2015
class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme):
2016
r"""
2017
Construct an algebraic subscheme of a toric variety.
2018
2019
.. WARNING::
2020
2021
You should not create objects of this class directly. The
2022
preferred method to construct such subschemes is to use
2023
:meth:`~ToricVariety_field.subscheme` method of :class:`toric
2024
varieties
2025
<sage.schemes.toric.variety.ToricVariety_field>`.
2026
2027
INPUT:
2028
2029
- ``toric_variety`` -- ambient :class:`toric variety
2030
<ToricVariety_field>`;
2031
2032
- ``polynomials`` -- single polynomial, list, or ideal of defining
2033
polynomials in the coordinate ring of ``toric_variety``.
2034
2035
OUTPUT:
2036
2037
- :class:`algebraic subscheme of a toric variety
2038
<AlgebraicScheme_subscheme_toric>`.
2039
2040
TESTS::
2041
2042
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2043
sage: P1xP1 = ToricVariety(fan, "x s y t")
2044
sage: P1xP1.inject_variables()
2045
Defining x, s, y, t
2046
sage: import sage.schemes.generic.algebraic_scheme as SCM
2047
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2048
... P1xP1, [x*s + y*t, x^3+y^3])
2049
sage: X
2050
Closed subscheme of 2-d toric variety
2051
covered by 4 affine patches defined by:
2052
x*s + y*t,
2053
x^3 + y^3
2054
2055
A better way to construct the same scheme as above::
2056
2057
sage: P1xP1.subscheme([x*s + y*t, x^3+y^3])
2058
Closed subscheme of 2-d toric variety
2059
covered by 4 affine patches defined by:
2060
x*s + y*t,
2061
x^3 + y^3
2062
"""
2063
2064
# Implementation note: if the toric variety is affine you should
2065
# construct instances of the derived class
2066
# AlgebraicScheme_subscheme_affine_toric instead.
2067
2068
def __init__(self, toric_variety, polynomials):
2069
r"""
2070
See :class:`AlgebraicScheme_subscheme_toric` for documentation.
2071
2072
TESTS::
2073
2074
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2075
sage: P1xP1 = ToricVariety(fan, "x s y t")
2076
sage: P1xP1.inject_variables()
2077
Defining x, s, y, t
2078
sage: import sage.schemes.generic.algebraic_scheme as SCM
2079
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2080
... P1xP1, [x*s + y*t, x^3+y^3])
2081
sage: X
2082
Closed subscheme of 2-d toric variety
2083
covered by 4 affine patches defined by:
2084
x*s + y*t,
2085
x^3 + y^3
2086
"""
2087
# Just to make sure that keyword arguments will be passed correctly
2088
super(AlgebraicScheme_subscheme_toric, self).__init__(toric_variety,
2089
polynomials)
2090
2091
def _morphism(self, *args, **kwds):
2092
r"""
2093
Construct a morphism determined by action on points of ``self``.
2094
2095
INPUT:
2096
2097
- same as for
2098
:class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`.
2099
2100
OUPUT:
2101
2102
- :class:`~sage.schemes.toric.morphism.SchemeMorphism_polynomial_toric_variety`.
2103
2104
TESTS::
2105
2106
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2107
sage: P1xP1 = ToricVariety(fan)
2108
sage: P1xP1.inject_variables()
2109
Defining z0, z1, z2, z3
2110
sage: P1 = P1xP1.subscheme(z0-z2)
2111
sage: H = P1.Hom(P1xP1)
2112
sage: H([z0,z1,z0,z3])
2113
Scheme morphism:
2114
From: Closed subscheme of 2-d toric variety
2115
covered by 4 affine patches defined by:
2116
z0 - z2
2117
To: 2-d toric variety covered by 4 affine patches
2118
Defn: Defined on coordinates by sending [z0 : z1 : z2 : z3] to
2119
[z2 : z1 : z2 : z3]
2120
2121
sage: P1._morphism(H, [z0,z1,z0,z3])
2122
Scheme morphism:
2123
From: Closed subscheme of 2-d toric variety
2124
covered by 4 affine patches defined by:
2125
z0 - z2
2126
To: 2-d toric variety covered by 4 affine patches
2127
Defn: Defined on coordinates by sending [z0 : z1 : z2 : z3] to
2128
[z2 : z1 : z2 : z3]
2129
"""
2130
from sage.schemes.toric.morphism import SchemeMorphism_polynomial_toric_variety
2131
return SchemeMorphism_polynomial_toric_variety(*args, **kwds)
2132
2133
def fan(self):
2134
"""
2135
Return the fan of the ambient space.
2136
2137
OUTPUT:
2138
2139
A fan.
2140
2141
EXAMPLES::
2142
2143
sage: P2.<x,y,z> = toric_varieties.P(2)
2144
sage: E = P2.subscheme([x^2+y^2+z^2])
2145
sage: E.fan()
2146
Rational polyhedral fan in 2-d lattice N
2147
"""
2148
return self.ambient_space().fan()
2149
2150
def affine_patch(self, i):
2151
r"""
2152
Return the ``i``-th affine patch of ``self`` as an affine
2153
toric algebraic scheme.
2154
2155
INPUT:
2156
2157
- ``i`` -- integer, index of a generating cone of the fan of the
2158
ambient space of ``self``.
2159
2160
OUTPUT:
2161
2162
- subscheme of an affine :class:`toric variety
2163
<sage.schemes.toric.variety.ToricVariety_field>`
2164
corresponding to the pull-back of ``self`` by the embedding
2165
morphism of the ``i``-th :meth:`affine patch of the ambient
2166
space
2167
<sage.schemes.toric.variety.ToricVariety_field.affine_patch>`
2168
of ``self``.
2169
2170
The result is cached, so the ``i``-th patch is always the same object
2171
in memory.
2172
2173
EXAMPLES::
2174
2175
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2176
sage: P1xP1 = ToricVariety(fan, "x s y t")
2177
sage: patch1 = P1xP1.affine_patch(1)
2178
sage: patch1.embedding_morphism()
2179
Scheme morphism:
2180
From: 2-d affine toric variety
2181
To: 2-d toric variety covered by 4 affine patches
2182
Defn: Defined on coordinates by sending [y : t] to
2183
[1 : 1 : y : t]
2184
sage: P1xP1.inject_variables()
2185
Defining x, s, y, t
2186
sage: P1 = P1xP1.subscheme(x-y)
2187
sage: subpatch = P1.affine_patch(1)
2188
sage: subpatch
2189
Closed subscheme of 2-d affine toric variety defined by:
2190
-y + 1
2191
"""
2192
i = int(i) # implicit type checking
2193
try:
2194
return self._affine_patches[i]
2195
except AttributeError:
2196
self._affine_patches = dict()
2197
except KeyError:
2198
pass
2199
ambient_patch = self.ambient_space().affine_patch(i)
2200
phi_p = ambient_patch.embedding_morphism().defining_polynomials()
2201
patch = ambient_patch.subscheme(
2202
[p(phi_p) for p in self.defining_polynomials()])
2203
patch._embedding_morphism = patch.hom(phi_p, self, check=False)
2204
self._affine_patches[i] = patch
2205
return patch
2206
2207
def affine_algebraic_patch(self, cone=None, names=None):
2208
r"""
2209
Return the affine patch corresponding to ``cone`` as an affine
2210
algebraic scheme.
2211
2212
INPUT:
2213
2214
- ``cone`` -- a :class:`Cone
2215
<sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma`
2216
of the fan. It can be omitted for an affine toric variety,
2217
in which case the single generating cone is used.
2218
2219
OUTPUT:
2220
2221
An :class:`affine algebraic subscheme
2222
<sage.schemes.generic.algebraic_scheme.AlgebraicScheme_subscheme_affine>`
2223
corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)`
2224
associated to the cone `\sigma`.
2225
2226
See also :meth:`affine_patch`, which expresses the patches as
2227
subvarieties of affine toric varieties instead.
2228
2229
REFERENCES:
2230
2231
..
2232
2233
David A. Cox, "The Homogeneous Coordinate Ring of a Toric
2234
Variety", Lemma 2.2.
2235
http://www.arxiv.org/abs/alg-geom/9210008v2
2236
2237
EXAMPLES::
2238
2239
sage: P2.<x,y,z> = toric_varieties.P2()
2240
sage: cone = P2.fan().generating_cone(0)
2241
sage: V = P2.subscheme(x^3+y^3+z^3)
2242
sage: V.affine_algebraic_patch(cone)
2243
Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
2244
z0^3 + z1^3 + 1
2245
2246
sage: cone = Cone([(0,1),(2,1)])
2247
sage: A2Z2.<x,y> = AffineToricVariety(cone)
2248
sage: A2Z2.affine_algebraic_patch()
2249
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2250
-z0*z1 + z2^2
2251
sage: V = A2Z2.subscheme(x^2+y^2-1)
2252
sage: patch = V.affine_algebraic_patch(); patch
2253
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2254
-z0*z1 + z2^2,
2255
z0 + z1 - 1
2256
sage: nbhd_patch = V.neighborhood([1,0]).affine_algebraic_patch(); nbhd_patch
2257
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2258
-z0*z1 + z2^2,
2259
z0 + z1 - 1
2260
sage: nbhd_patch.embedding_center()
2261
(0, 1, 0)
2262
2263
Here we got two defining equations. The first one describes
2264
the singularity of the ambient space and the second is the
2265
pull-back of `x^2+y^2-1` ::
2266
2267
sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)])
2268
sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp)
2269
sage: Y = X.subscheme(x*v+y*u+t)
2270
sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)])
2271
sage: Y.affine_algebraic_patch(cone)
2272
Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
2273
z0*z2 - z1*z3,
2274
z1 + z3 + 1
2275
"""
2276
from sage.modules.all import vector
2277
from sage.misc.all import prod
2278
ambient = self.ambient_space()
2279
fan = ambient.fan()
2280
if cone is None:
2281
assert ambient.is_affine()
2282
cone = fan.generating_cone(0)
2283
else:
2284
cone = fan.embed(cone)
2285
# R/I = C[sigma^dual cap M]
2286
R, I, dualcone = ambient._semigroup_ring(cone, names)
2287
2288
# inhomogenize the Cox homogeneous polynomial with respect to the given cone
2289
inhomogenize = dict( (ambient.coordinate_ring().gen(i), 1)
2290
for i in range(0,fan.nrays())
2291
if not i in cone.ambient_ray_indices() )
2292
polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ]
2293
2294
# map the monomial x^{D_m} to m, see reference.
2295
n_rho_matrix = cone.ray_matrix()
2296
def pullback_polynomial(p):
2297
result = R.zero()
2298
for coefficient, monomial in p:
2299
exponent = monomial.exponents()[0]
2300
exponent = [ exponent[i] for i in cone.ambient_ray_indices() ]
2301
exponent = vector(ZZ,exponent)
2302
m = n_rho_matrix.solve_left(exponent)
2303
assert all(x in ZZ for x in m), \
2304
'The polynomial '+str(p)+' does not define a ZZ-divisor!'
2305
m_coeffs = dualcone.Hilbert_coefficients(m)
2306
result += coefficient * prod(R.gen(i)**m_coeffs[i]
2307
for i in range(0,R.ngens()))
2308
return result
2309
2310
# construct the affine algebraic scheme to use as patch
2311
polynomials = map(pullback_polynomial, polynomials)
2312
patch_cover = affine_space.AffineSpace(R)
2313
polynomials = list(I.gens()) + polynomials
2314
polynomials = filter( lambda x:not x.is_zero(), polynomials)
2315
patch = patch_cover.subscheme(polynomials)
2316
2317
# TODO: If the cone is not smooth, then the coordinate_ring()
2318
# of the affine toric variety is wrong; it should be the
2319
# G-invariant part. So we can't construct the embedding
2320
# morphism in that case.
2321
if cone.is_smooth():
2322
x = ambient.coordinate_ring().gens()
2323
phi = []
2324
for i in range(0,fan.nrays()):
2325
if i in cone.ambient_ray_indices():
2326
phi.append(pullback_polynomial(x[i]))
2327
else:
2328
phi.append(1)
2329
patch._embedding_morphism = patch.hom(phi, self)
2330
else:
2331
patch._embedding_morphism = (NotImplementedError,
2332
'I only know how to construct embedding morphisms for smooth patches')
2333
2334
try:
2335
point = self.embedding_center()
2336
except AttributeError:
2337
return patch
2338
2339
# it remains to find the preimage of point
2340
# map m to the monomial x^{D_m}, see reference.
2341
F = ambient.coordinate_ring().fraction_field()
2342
image = []
2343
for m in dualcone.Hilbert_basis():
2344
x_Dm = prod([ F.gen(i)**(m*n) for i,n in enumerate(fan.rays()) ])
2345
image.append(x_Dm)
2346
patch._embedding_center = tuple( f(list(point)) for f in image )
2347
return patch
2348
2349
def _best_affine_patch(self, point):
2350
r"""
2351
Return the best affine patch of the ambient toric variety.
2352
2353
INPUT:
2354
2355
- ``point`` -- a point of the algebraic subscheme.
2356
2357
OUTPUT:
2358
2359
Integer. The index of the patch. See :meth:`affine_patch`.
2360
2361
EXAMPLES::
2362
2363
sage: P.<x,y,z>= toric_varieties.P2()
2364
sage: S = P.subscheme(x+2*y+3*z)
2365
sage: S._best_affine_patch(P.point([2,-3,0]))
2366
1
2367
sage: S._best_affine_patch([2,-3,0])
2368
1
2369
"""
2370
# TODO: this method should pick a "best" patch in the sense
2371
# that it is numerically stable to dehomogenize, see the
2372
# corresponding method for projective varieties.
2373
point = list(point)
2374
zeros = set(i for i, coord in enumerate(point) if coord == 0)
2375
for cone_idx, cone in enumerate(self.ambient_space().fan().generating_cones()):
2376
if zeros.issubset(cone.ambient_ray_indices()):
2377
return cone_idx
2378
assert False, 'The point must not have been a point of the toric variety.'
2379
2380
def neighborhood(self, point):
2381
r"""
2382
Return an toric algebraic scheme isomorphic to neighborhood of
2383
the ``point``.
2384
2385
INPUT:
2386
2387
- ``point`` -- a point of the toric algebraic scheme.
2388
2389
OUTPUT
2390
2391
An affine toric algebraic scheme (polynomial equations in an
2392
affine toric variety) with fixed
2393
:meth:`~AlgebraicScheme.embedding_morphism` and
2394
:meth:`~AlgebraicScheme.embedding_center`.
2395
2396
EXAMPLES::
2397
2398
sage: P.<x,y,z>= toric_varieties.P2()
2399
sage: S = P.subscheme(x+2*y+3*z)
2400
sage: s = S.point([0,-3,2]); s
2401
[0 : -3 : 2]
2402
sage: patch = S.neighborhood(s); patch
2403
Closed subscheme of 2-d affine toric variety defined by:
2404
x + 2*y + 6
2405
sage: patch.embedding_morphism()
2406
Scheme morphism:
2407
From: Closed subscheme of 2-d affine toric variety defined by:
2408
x + 2*y + 6
2409
To: Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by:
2410
x + 2*y + 3*z
2411
Defn: Defined on coordinates by sending [x : y] to
2412
[-2*y - 6 : y : 2]
2413
sage: patch.embedding_center()
2414
[0 : -3]
2415
sage: patch.embedding_morphism()(patch.embedding_center())
2416
[0 : -3 : 2]
2417
2418
A more complicated example::
2419
2420
sage: dP6.<x0,x1,x2,x3,x4,x5> = toric_varieties.dP6()
2421
sage: twoP1 = dP6.subscheme(x0*x3)
2422
sage: patch = twoP1.neighborhood([0,1,2, 3,4,5]); patch
2423
Closed subscheme of 2-d affine toric variety defined by:
2424
3*x0
2425
sage: patch.embedding_morphism()
2426
Scheme morphism:
2427
From: Closed subscheme of 2-d affine toric variety defined by:
2428
3*x0
2429
To: Closed subscheme of 2-d CPR-Fano toric variety covered by 6 affine patches defined by:
2430
x0*x3
2431
Defn: Defined on coordinates by sending [x0 : x1] to
2432
[0 : x1 : 2 : 3 : 4 : 5]
2433
sage: patch.embedding_center()
2434
[0 : 1]
2435
sage: patch.embedding_morphism()(patch.embedding_center())
2436
[0 : 1 : 2 : 3 : 4 : 5]
2437
"""
2438
point = list(point)
2439
self._check_satisfies_equations(point)
2440
PP = self.ambient_space()
2441
n = PP.dimension()
2442
fan = PP.fan()
2443
cone_idx = self._best_affine_patch(point)
2444
cone = fan.generating_cone(cone_idx)
2445
2446
patch_cover = PP.affine_patch(cone_idx)
2447
R = patch_cover.coordinate_ring()
2448
phi = []
2449
point_preimage = []
2450
for i in range(0,fan.nrays()):
2451
try:
2452
ray_index = cone.ambient_ray_indices().index(i)
2453
phi.append(R.gen(ray_index))
2454
point_preimage.append(point[i])
2455
except ValueError:
2456
phi.append(point[i])
2457
pullback_polys = [f(phi) for f in self.defining_polynomials()]
2458
patch = patch_cover.subscheme(pullback_polys)
2459
2460
patch._embedding_center = patch(point_preimage)
2461
patch._embedding_morphism = patch.hom(phi,self)
2462
return patch
2463
2464
def dimension(self):
2465
"""
2466
Return the dimension of ``self``.
2467
2468
OUTPUT:
2469
2470
Integer. If ``self`` is empty, `-1` is returned.
2471
2472
EXAMPLES::
2473
2474
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2475
sage: P1xP1 = ToricVariety(fan)
2476
sage: P1xP1.inject_variables()
2477
Defining z0, z1, z2, z3
2478
sage: P1 = P1xP1.subscheme(z0-z2)
2479
sage: P1.dimension()
2480
1
2481
sage: P1xP1.subscheme([z0-z2, (z0-z2)^2]).dimension()
2482
1
2483
sage: P1xP1.subscheme([z0,z2]).dimension()
2484
-1
2485
"""
2486
if '_dimension' in self.__dict__:
2487
return self._dimension
2488
npatches = self.ambient_space().fan().ngenerating_cones()
2489
dims = [ self.affine_patch(i).dimension() for i in range(0,npatches) ]
2490
self._dimension = max(dims)
2491
return self._dimension
2492
2493
def is_smooth(self, point=None):
2494
r"""
2495
Test whether the algebraic subscheme is smooth.
2496
2497
INPUT:
2498
2499
- ``point`` -- A point or ``None`` (default). The point to
2500
test smoothness at.
2501
2502
OUTPUT:
2503
2504
Boolean. If no point was specified, returns whether the
2505
algebraic subscheme is smooth everywhere. Otherwise,
2506
smoothness at the specified point is tested.
2507
2508
EXAMPLES::
2509
2510
sage: P2.<x,y,z> = toric_varieties.P2()
2511
sage: cuspidal_curve = P2.subscheme([y^2*z-x^3])
2512
sage: cuspidal_curve
2513
Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by:
2514
-x^3 + y^2*z
2515
sage: cuspidal_curve.is_smooth([1,1,1])
2516
True
2517
sage: cuspidal_curve.is_smooth([0,0,1])
2518
False
2519
sage: cuspidal_curve.is_smooth()
2520
False
2521
2522
Any sufficiently generic cubic hypersurface is smooth::
2523
2524
sage: P2.subscheme([y^2*z-x^3+z^3+1/10*x*y*z]).is_smooth()
2525
True
2526
2527
A more complicated example::
2528
2529
sage: dP6.<x0,x1,x2,x3,x4,x5> = toric_varieties.dP6()
2530
sage: disjointP1s = dP6.subscheme(x0*x3)
2531
sage: disjointP1s.is_smooth()
2532
True
2533
sage: intersectingP1s = dP6.subscheme(x0*x1)
2534
sage: intersectingP1s.is_smooth()
2535
False
2536
2537
A smooth hypersurface in a compact singular toric variety::
2538
2539
sage: lp = LatticePolytope(matrix([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)]).transpose())
2540
sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp)
2541
sage: Y = X.subscheme(x*v+y*u+t)
2542
sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)])
2543
sage: Y.is_smooth()
2544
True
2545
"""
2546
if not point is None:
2547
toric_patch = self.neighborhood(point)
2548
return toric_patch.is_smooth(toric_patch.embedding_center())
2549
2550
# testing smoothness everywhere tends to be expensive
2551
if '_smooth' in self.__dict__:
2552
return self._smooth
2553
npatches = self.ambient_space().fan().ngenerating_cones()
2554
self._smooth = all(self.affine_patch(i).is_smooth() for i in range(0,npatches))
2555
return self._smooth
2556
2557
2558
class AlgebraicScheme_subscheme_affine_toric(AlgebraicScheme_subscheme_toric):
2559
r"""
2560
Construct an algebraic subscheme of an affine toric variety.
2561
2562
.. WARNING::
2563
2564
You should not create objects of this class directly. The preferred
2565
method to construct such subschemes is to use
2566
:meth:`~ToricVariety_field.subscheme` method of
2567
:class:`toric varieties <ToricVariety_field>`.
2568
2569
INPUT:
2570
2571
- ``toric_variety`` -- ambient :class:`affine toric variety
2572
<ToricVariety_field>`;
2573
2574
- ``polynomials`` -- single polynomial, list, or ideal of defining
2575
polynomials in the coordinate ring of ``toric_variety``.
2576
2577
OUTPUT:
2578
2579
A :class:`algebraic subscheme of an affine toric variety
2580
<AlgebraicScheme_subscheme_affine_toric>`.
2581
2582
TESTS::
2583
2584
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2585
sage: P1xP1 = ToricVariety(fan, "x s y t")
2586
sage: P1xP1.inject_variables()
2587
Defining x, s, y, t
2588
sage: import sage.schemes.generic.algebraic_scheme as SCM
2589
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2590
... P1xP1, [x*s + y*t, x^3+y^3])
2591
sage: X
2592
Closed subscheme of 2-d toric variety
2593
covered by 4 affine patches defined by:
2594
x*s + y*t,
2595
x^3 + y^3
2596
2597
A better way to construct the same scheme as above::
2598
2599
sage: P1xP1.subscheme([x*s + y*t, x^3+y^3])
2600
Closed subscheme of 2-d toric variety
2601
covered by 4 affine patches defined by:
2602
x*s + y*t,
2603
x^3 + y^3
2604
"""
2605
2606
def __init__(self, toric_variety, polynomials):
2607
r"""
2608
See :class:`AlgebraicScheme_subscheme_toric` for documentation.
2609
2610
TESTS::
2611
2612
sage: fan = FaceFan(lattice_polytope.octahedron(2))
2613
sage: P1xP1 = ToricVariety(fan, "x s y t")
2614
sage: P1xP1.inject_variables()
2615
Defining x, s, y, t
2616
sage: import sage.schemes.generic.algebraic_scheme as SCM
2617
sage: X = SCM.AlgebraicScheme_subscheme_toric(
2618
... P1xP1, [x*s + y*t, x^3+y^3])
2619
sage: X
2620
Closed subscheme of 2-d toric variety
2621
covered by 4 affine patches defined by:
2622
x*s + y*t,
2623
x^3 + y^3
2624
"""
2625
assert toric_variety.is_affine(), 'The toric variety must be affine!'
2626
# Just to make sure that keyword arguments will be passed correctly
2627
super(AlgebraicScheme_subscheme_affine_toric, self).__init__(toric_variety,
2628
polynomials)
2629
2630
def dimension(self):
2631
"""
2632
Return the dimension of ``self``.
2633
2634
OUTPUT:
2635
2636
- integer.
2637
2638
EXAMPLES::
2639
2640
sage: P1xP1.<s0,s1,t0,t1> = toric_varieties.P1xP1()
2641
sage: P1 = P1xP1.subscheme(s0-s1)
2642
sage: P1.dimension()
2643
1
2644
2645
A more complicated example where the ambient toric variety is
2646
not smooth::
2647
2648
sage: X.<x,y> = toric_varieties.A2_Z2()
2649
sage: X.is_smooth()
2650
False
2651
sage: Y = X.subscheme([x*y, x^2])
2652
sage: Y
2653
Closed subscheme of 2-d affine toric variety defined by:
2654
x*y,
2655
x^2
2656
sage: Y.dimension()
2657
1
2658
"""
2659
if '_dimension' in self.__dict__:
2660
return self._dimension
2661
2662
if self.ambient_space().is_smooth():
2663
self._dimension = self.defining_ideal().dimension()
2664
else:
2665
self._dimension = self.affine_algebraic_patch().dimension()
2666
return self._dimension
2667
2668
def is_smooth(self, point=None):
2669
r"""
2670
Test whether the algebraic subscheme is smooth.
2671
2672
INPUT:
2673
2674
- ``point`` -- A point or ``None`` (default). The point to
2675
test smoothness at.
2676
2677
OUTPUT:
2678
2679
Boolean. If no point was specified, returns whether the
2680
algebraic subscheme is smooth everywhere. Otherwise,
2681
smoothness at the specified point is tested.
2682
2683
EXAMPLES::
2684
2685
sage: A2.<x,y> = toric_varieties.A2()
2686
sage: cuspidal_curve = A2.subscheme([y^2-x^3])
2687
sage: cuspidal_curve
2688
Closed subscheme of 2-d affine toric variety defined by:
2689
-x^3 + y^2
2690
sage: cuspidal_curve.is_smooth([1,1])
2691
True
2692
sage: cuspidal_curve.is_smooth([0,0])
2693
False
2694
sage: cuspidal_curve.is_smooth()
2695
False
2696
sage: circle = A2.subscheme(x^2+y^2-1)
2697
sage: circle.is_smooth([1,0])
2698
True
2699
sage: circle.is_smooth()
2700
True
2701
2702
A more complicated example where the ambient toric variety is
2703
not smooth::
2704
2705
sage: X.<x,y> = toric_varieties.A2_Z2() # 2-d affine space mod Z/2
2706
sage: X.is_smooth()
2707
False
2708
sage: Y = X.subscheme([x*y, x^2]) # (twice the x=0 curve) mod Z/2
2709
sage: Y
2710
Closed subscheme of 2-d affine toric variety defined by:
2711
x*y,
2712
x^2
2713
sage: Y.dimension() # Y is a Weil divisor but not Cartier
2714
1
2715
sage: Y.is_smooth()
2716
True
2717
sage: Y.is_smooth([0,0])
2718
True
2719
"""
2720
if not point is None:
2721
self._check_satisfies_equations(point)
2722
if self.ambient_space().is_smooth():
2723
R = self.ambient_space().coordinate_ring()
2724
point_subs = dict(zip(R.gens(), point))
2725
Jac = self.Jacobian().subs(point_subs)
2726
return not Jac.is_zero()
2727
else:
2728
self._embedding_center = self.point(point)
2729
affine = self.affine_algebraic_patch()
2730
return affine.is_smooth(affine.embedding_center())
2731
2732
# testing smoothness everywhere tends to be expensive
2733
if '_smooth' in self.__dict__:
2734
return self._smooth
2735
2736
if self.ambient_space().is_smooth():
2737
sing_dim = self.Jacobian().dimension()
2738
self._smooth = (sing_dim == -1)
2739
else:
2740
self._smooth = self.affine_algebraic_patch().is_smooth()
2741
2742
return self._smooth
2743
2744
2745
2746
2747