Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/toric/variety.py
4107 views
1
r"""
2
Toric varieties
3
4
This module provides support for (normal) toric varieties, corresponding to
5
:class:`rational polyhedral fans <sage.geometry.fan.RationalPolyhedralFan>`.
6
See also :mod:`~sage.schemes.toric.fano_variety` for a more
7
restrictive class of (weak) Fano toric varieties.
8
9
An **excellent reference on toric varieties** is the book "Toric
10
Varieties" by David A. Cox, John B. Little, and Hal Schenck
11
[CLS]_.
12
13
The interface to this module is provided through functions
14
:func:`AffineToricVariety` and :func:`ToricVariety`, although you may
15
also be interested in :func:`normalize_names`.
16
17
.. NOTE::
18
19
We do NOT build "general toric varieties" from affine toric varieties.
20
Instead, we are using the quotient representation of toric varieties with
21
the homogeneous coordinate ring (a.k.a. Cox's ring or the total coordinate
22
ring). This description works best for simplicial fans of the full
23
dimension.
24
25
REFERENCES:
26
27
.. [CLS]
28
David A. Cox, John B. Little, Hal Schenck,
29
"Toric Varieties", Graduate Studies in Mathematics,
30
Amer. Math. Soc., Providence, RI, 2011
31
32
AUTHORS:
33
34
- Andrey Novoseltsev (2010-05-17): initial version.
35
36
- Volker Braun (2010-07-24): Cohomology and characteristic classes added.
37
38
EXAMPLES:
39
40
We start with constructing the affine plane as an affine toric variety. First,
41
we need to have a corresponding cone::
42
43
sage: quadrant = Cone([(1,0), (0,1)])
44
45
If you don't care about variable names and the base field, that's all we need
46
for now::
47
48
sage: A2 = AffineToricVariety(quadrant)
49
sage: A2
50
2-d affine toric variety
51
sage: origin = A2(0,0)
52
sage: origin
53
[0 : 0]
54
55
Only affine toric varieties have points whose (homogeneous) coordinates
56
are all zero. ::
57
58
sage: parent(origin)
59
Set of rational points of 2-d affine toric variety
60
61
As you can see, by default toric varieties live over the field of rational
62
numbers::
63
64
sage: A2.base_ring()
65
Rational Field
66
67
While usually toric varieties are considered over the field of complex
68
numbers, for computational purposes it is more convenient to work with fields
69
that have exact representation on computers. You can also always do ::
70
71
sage: C2 = AffineToricVariety(quadrant, base_field=CC)
72
sage: C2.base_ring()
73
Complex Field with 53 bits of precision
74
sage: C2(1,2+i)
75
[1.00000000000000 : 2.00000000000000 + 1.00000000000000*I]
76
77
or even ::
78
79
sage: F = CC["a, b"].fraction_field()
80
sage: F.inject_variables()
81
Defining a, b
82
sage: A2 = AffineToricVariety(quadrant, base_field=F)
83
sage: A2(a,b)
84
[a : b]
85
86
OK, if you need to work only with affine spaces,
87
:func:`~sage.schemes.generic.affine_space.AffineSpace` may be a better way to
88
construct them. Our next example is the product of two projective lines
89
realized as the toric variety associated to the
90
:func:`face fan <sage.geometry.fan.FaceFan>` of the "diamond"::
91
92
sage: diamond = lattice_polytope.octahedron(2)
93
sage: diamond.vertices()
94
[ 1 0 -1 0]
95
[ 0 1 0 -1]
96
sage: fan = FaceFan(diamond)
97
sage: P1xP1 = ToricVariety(fan)
98
sage: P1xP1
99
2-d toric variety covered by 4 affine patches
100
sage: P1xP1.fan().ray_matrix()
101
[ 1 0 -1 0]
102
[ 0 1 0 -1]
103
sage: P1xP1.gens()
104
(z0, z1, z2, z3)
105
106
We got four coordinates - two for each of the projective lines, but their
107
names are perhaps not very well chosen. Let's make `(x,y)` to be coordinates
108
on the first line and `(s,t)` on the second one::
109
110
sage: P1xP1 = ToricVariety(fan, coordinate_names="x s y t")
111
sage: P1xP1.gens()
112
(x, s, y, t)
113
114
Now, if we want to define subschemes of this variety, the defining polynomials
115
must be homogeneous in each of these pairs::
116
117
sage: P1xP1.inject_variables()
118
Defining x, s, y, t
119
sage: P1xP1.subscheme(x)
120
Closed subscheme of 2-d toric variety
121
covered by 4 affine patches defined by:
122
x
123
sage: P1xP1.subscheme(x^2 + y^2)
124
Closed subscheme of 2-d toric variety
125
covered by 4 affine patches defined by:
126
x^2 + y^2
127
sage: P1xP1.subscheme(x^2 + s^2)
128
Traceback (most recent call last):
129
...
130
ValueError: x^2 + s^2 is not homogeneous
131
on 2-d toric variety covered by 4 affine patches!
132
sage: P1xP1.subscheme([x^2*s^2 + x*y*t^2 +y^2*t^2, s^3 + t^3])
133
Closed subscheme of 2-d toric variety
134
covered by 4 affine patches defined by:
135
x^2*s^2 + x*y*t^2 + y^2*t^2,
136
s^3 + t^3
137
138
While we don't build toric varieties from affine toric varieties, we still can
139
access the "building pieces"::
140
141
sage: patch = P1xP1.affine_patch(2)
142
sage: patch
143
2-d affine toric variety
144
sage: patch.fan().ray_matrix()
145
[1 0]
146
[0 1]
147
sage: patch.embedding_morphism()
148
Scheme morphism:
149
From: 2-d affine toric variety
150
To: 2-d toric variety covered by 4 affine patches
151
Defn: Defined on coordinates by sending [x : s] to
152
[x : s : 1 : 1]
153
154
The patch above was specifically chosen to coincide with our representation of
155
the affine plane before, but you can get the other three patches as well.
156
(While any cone of a fan will correspond to an affine toric variety, the main
157
interest is usually in the generating fans as "the biggest" affine
158
subvarieties, and these are precisely the patches that you can get from
159
:meth:`~ToricVariety_field.affine_patch`.)
160
161
All two-dimensional toric varieties are "quite nice" because any
162
two-dimensional cone is generated by exactly two rays. From the point of view
163
of the corresponding toric varieties, this means that they have at worst
164
quotient singularities::
165
166
sage: P1xP1.is_orbifold()
167
True
168
sage: P1xP1.is_smooth()
169
True
170
sage: TV = ToricVariety(NormalFan(diamond))
171
sage: TV.fan().ray_matrix()
172
[-1 1 -1 1]
173
[ 1 1 -1 -1]
174
sage: TV.is_orbifold()
175
True
176
sage: TV.is_smooth()
177
False
178
179
In higher dimensions worse things can happen::
180
181
sage: TV3 = ToricVariety(NormalFan(lattice_polytope.octahedron(3)))
182
sage: TV3.fan().ray_matrix()
183
[-1 1 -1 1 -1 1 -1 1]
184
[-1 -1 1 1 -1 -1 1 1]
185
[ 1 1 1 1 -1 -1 -1 -1]
186
sage: TV3.is_orbifold()
187
False
188
189
Fortunately, we can perform a (partial) resolution::
190
191
sage: TV3_res = TV3.resolve_to_orbifold()
192
sage: TV3_res.is_orbifold()
193
True
194
sage: TV3_res.fan().ngenerating_cones()
195
12
196
sage: TV3.fan().ngenerating_cones()
197
6
198
199
In this example we had to double the number of affine patches. The result is
200
still singular::
201
202
sage: TV3_res.is_smooth()
203
False
204
205
You can resolve it further using :meth:`~ToricVariety_field.resolve` method,
206
but (at least for now) you will have to specify which rays should be inserted
207
into the fan. See also
208
:func:`~sage.schemes.toric.fano_variety.CPRFanoToricVariety`,
209
which can construct some other "nice partial resolutions."
210
211
The intersection theory on toric varieties is very well understood,
212
and there are explicit algorithms to compute many quantities of
213
interest. The most important tools are the :class:`cohomology ring
214
<CohomologyRing>` and the :mod:`Chow group
215
<sage.schemes.toric.chow_group>`. For `d`-dimensional compact
216
toric varieties with at most orbifold singularities, the rational
217
cohomology ring `H^*(X,\QQ)` and the rational Chow ring `A^*(X,\QQ) =
218
A_{d-*}(X)\otimes \QQ` are isomorphic except for a doubling in
219
degree. More precisely, the Chow group has the same rank
220
221
.. math::
222
223
A_{d-k}(X) \otimes \QQ \simeq H^{2k}(X,\QQ)
224
225
and the intersection in of Chow cycles matches the cup product in
226
cohomology.
227
228
In this case, you should work with the cohomology ring description
229
because it is much faster. For example, here is a weighted projective
230
space with a curve of `\ZZ_3`-orbifold singularities::
231
232
sage: P4_11133 = toric_varieties.P4_11133()
233
sage: P4_11133.is_smooth(), P4_11133.is_orbifold()
234
(False, True)
235
sage: cone = P4_11133.fan(3)[8]
236
sage: cone.is_smooth(), cone.is_simplicial()
237
(False, True)
238
sage: HH = P4_11133.cohomology_ring(); HH
239
Rational cohomology ring of a 4-d CPR-Fano toric variety covered by 5 affine patches
240
sage: P4_11133.cohomology_basis()
241
(([1],), ([z4],), ([z4^2],), ([z4^3],), ([z4^4],))
242
243
Every cone defines a torus orbit closure, and hence a (co)homology class::
244
245
sage: HH.gens()
246
([3*z4], [3*z4], [z4], [z4], [z4])
247
sage: map(HH, P4_11133.fan(1))
248
[[3*z4], [3*z4], [z4], [z4], [z4]]
249
sage: map(HH, P4_11133.fan(4) )
250
[[9*z4^4], [9*z4^4], [9*z4^4], [9*z4^4], [9*z4^4]]
251
sage: HH(cone)
252
[3*z4^3]
253
254
We can compute intersection numbers by integrating top-dimensional
255
cohomology classes::
256
257
sage: D = P4_11133.divisor(0)
258
sage: HH(D)
259
[3*z4]
260
sage: P4_11133.integrate( HH(D)^4 )
261
9
262
sage: P4_11133.integrate( HH(D) * HH(cone) )
263
1
264
265
Although computationally less efficient, we can do the same
266
computations with the rational Chow group::
267
268
sage: AA = P4_11133.Chow_group(QQ)
269
sage: map(AA, P4_11133.fan(1))
270
[( 0 | 0 | 0 | 3 | 0 ), ( 0 | 0 | 0 | 3 | 0 ), ( 0 | 0 | 0 | 1 | 0 ), ( 0 | 0 | 0 | 1 | 0 ), ( 0 | 0 | 0 | 1 | 0 )]
271
sage: map(AA, P4_11133.fan(4))
272
[( 1 | 0 | 0 | 0 | 0 ), ( 1 | 0 | 0 | 0 | 0 ), ( 1 | 0 | 0 | 0 | 0 ), ( 1 | 0 | 0 | 0 | 0 ), ( 1 | 0 | 0 | 0 | 0 )]
273
sage: AA(cone).intersection_with_divisor(D)
274
( 1 | 0 | 0 | 0 | 0 )
275
sage: AA(cone).intersection_with_divisor(D).count_points()
276
1
277
278
The real advantage of the Chow group is that
279
280
* it works just as well over `\ZZ`, so torsion information is also
281
easily available, and
282
283
* its combinatorial description also works over worse-than-orbifold
284
singularities. By contrast, the cohomology groups can become very
285
complicated to compute in this case, and one usually only has a
286
spectral sequence but no toric algorithm.
287
288
Below you will find detailed descriptions of available functions. If you are
289
familiar with toric geometry, you will likely see that many important objects
290
and operations are unavailable. However, this module is under active
291
development and hopefully will improve in future releases of Sage. If there
292
are some particular features that you would like to see implemented ASAP,
293
please consider reporting them to the Sage Development Team or even
294
implementing them on your own as a patch for inclusion!
295
"""
296
297
298
#*****************************************************************************
299
# Copyright (C) 2010 Volker Braun <[email protected]>
300
# Copyright (C) 2010 Andrey Novoseltsev <[email protected]>
301
# Copyright (C) 2010 William Stein <[email protected]>
302
#
303
# Distributed under the terms of the GNU General Public License (GPL)
304
# as published by the Free Software Foundation; either version 2 of
305
# the License, or (at your option) any later version.
306
# http://www.gnu.org/licenses/
307
#*****************************************************************************
308
309
import sys
310
311
from sage.functions.all import factorial
312
from sage.geometry.cone import Cone, is_Cone
313
from sage.geometry.fan import Fan
314
from sage.matrix.all import matrix
315
from sage.misc.all import latex, prod, uniq, cached_method
316
from sage.structure.unique_representation import UniqueRepresentation
317
from sage.modules.free_module_element import vector
318
from sage.rings.all import PolynomialRing, ZZ, QQ, is_Field
319
from sage.rings.quotient_ring_element import QuotientRingElement
320
from sage.rings.quotient_ring import QuotientRing_generic
321
from sage.schemes.generic.affine_space import AffineSpace
322
from sage.schemes.generic.ambient_space import AmbientSpace
323
from sage.schemes.toric.homset import SchemeHomset_points_toric_field
324
325
326
327
# Default prefix for indexed coordinates
328
DEFAULT_PREFIX = "z"
329
330
331
def is_ToricVariety(x):
332
r"""
333
Check if ``x`` is a toric variety.
334
335
INPUT:
336
337
- ``x`` -- anything.
338
339
OUTPUT:
340
341
- ``True`` if ``x`` is a :class:`toric variety <ToricVariety_field>` and
342
``False`` otherwise.
343
344
.. NOTE::
345
346
While projective spaces are toric varieties mathematically, they are
347
not toric varieties in Sage due to efficiency considerations, so this
348
function will return ``False``.
349
350
EXAMPLES::
351
352
sage: from sage.schemes.toric.variety import is_ToricVariety
353
sage: is_ToricVariety(1)
354
False
355
sage: fan = FaceFan(lattice_polytope.octahedron(2))
356
sage: P = ToricVariety(fan)
357
sage: P
358
2-d toric variety covered by 4 affine patches
359
sage: is_ToricVariety(P)
360
True
361
sage: is_ToricVariety(ProjectiveSpace(2))
362
False
363
"""
364
return isinstance(x, ToricVariety_field)
365
366
367
def ToricVariety(fan,
368
coordinate_names=None,
369
names=None,
370
coordinate_indices=None,
371
base_field=QQ):
372
r"""
373
Construct a toric variety.
374
375
INPUT:
376
377
- ``fan`` -- :class:`rational polyhedral fan
378
<sage.geometry.fan.RationalPolyhedralFan>`;
379
380
- ``coordinate_names`` -- names of variables for the coordinate ring, see
381
:func:`normalize_names` for acceptable formats. If not given, indexed
382
variable names will be created automatically;
383
384
- ``names`` -- an alias of ``coordinate_names`` for internal
385
use. You may specify either ``names`` or ``coordinate_names``,
386
but not both;
387
388
- ``coordinate_indices`` -- list of integers, indices for indexed
389
variables. If not given, the index of each variable will coincide with
390
the index of the corresponding ray of the fan;
391
392
- ``base_field`` -- base field of the toric variety (default: `\QQ`).
393
394
OUTPUT:
395
396
- :class:`toric variety <ToricVariety_field>`.
397
398
EXAMPLES:
399
400
We will create the product of two projective lines::
401
402
sage: fan = FaceFan(lattice_polytope.octahedron(2))
403
sage: fan.ray_matrix()
404
[ 1 0 -1 0]
405
[ 0 1 0 -1]
406
sage: P1xP1 = ToricVariety(fan)
407
sage: P1xP1.gens()
408
(z0, z1, z2, z3)
409
410
Let's create some points::
411
412
sage: P1xP1(1,1,1,1)
413
[1 : 1 : 1 : 1]
414
sage: P1xP1(0,1,1,1)
415
[0 : 1 : 1 : 1]
416
sage: P1xP1(0,1,0,1)
417
Traceback (most recent call last):
418
...
419
TypeError: coordinates (0, 1, 0, 1)
420
are in the exceptional set!
421
422
We cannot set to zero both coordinates of the same projective line!
423
424
Let's change the names of the variables. We have to re-create our toric
425
variety::
426
427
sage: P1xP1 = ToricVariety(fan, "x s y t")
428
sage: P1xP1.gens()
429
(x, s, y, t)
430
431
Now `(x, y)` correspond to one line and `(s, t)` to the other one. ::
432
433
sage: P1xP1.inject_variables()
434
Defining x, s, y, t
435
sage: P1xP1.subscheme(x*s-y*t)
436
Closed subscheme of 2-d toric variety
437
covered by 4 affine patches defined by:
438
x*s - y*t
439
440
Here is a shorthand for defining the toric variety and homogeneous
441
coordinates in one go::
442
443
sage: P1xP1.<a,b,c,d> = ToricVariety(fan)
444
sage: (a^2+b^2) * (c+d)
445
a^2*c + b^2*c + a^2*d + b^2*d
446
"""
447
if names is not None:
448
if coordinate_names is not None:
449
raise ValueError('You must not specify both coordinate_names and names!')
450
coordinate_names = names
451
if not is_Field(base_field):
452
raise TypeError("need a field to construct a toric variety!\n Got %s"
453
% base_field)
454
return ToricVariety_field(fan, coordinate_names, coordinate_indices,
455
base_field)
456
457
458
def AffineToricVariety(cone, *args, **kwds):
459
r"""
460
Construct an affine toric variety.
461
462
INPUT:
463
464
- ``cone`` -- :class:`strictly convex rational polyhedral cone
465
<sage.geometry.cone.ConvexRationalPolyhedralCone>`.
466
467
This cone will be used to construct a :class:`rational polyhedral fan
468
<sage.geometry.fan.RationalPolyhedralFan>`, which will be passed to
469
:func:`ToricVariety` with the rest of positional and keyword arguments.
470
471
OUTPUT:
472
473
- :class:`toric variety <ToricVariety_field>`.
474
475
.. NOTE::
476
477
The generating rays of the fan of this variety are guaranteed to be
478
listed in the same order as the rays of the original cone.
479
480
EXAMPLES:
481
482
We will create the affine plane as an affine toric variety::
483
484
sage: quadrant = Cone([(1,0), (0,1)])
485
sage: A2 = AffineToricVariety(quadrant)
486
sage: origin = A2(0,0)
487
sage: origin
488
[0 : 0]
489
sage: parent(origin)
490
Set of rational points of 2-d affine toric variety
491
492
Only affine toric varieties have points whose (homogeneous) coordinates
493
are all zero.
494
"""
495
if not cone.is_strictly_convex():
496
raise ValueError("affine toric varieties are defined for strictly "
497
"convex cones only!")
498
# We make sure that Fan constructor does not meddle with the order of
499
# rays, this is very important for affine patches construction
500
fan = Fan([tuple(range(cone.nrays()))], cone.rays(),
501
check=False, normalize=False)
502
return ToricVariety(fan, *args, **kwds)
503
504
505
class ToricVariety_field(AmbientSpace):
506
r"""
507
Construct a toric variety associated to a rational polyhedral fan.
508
509
.. WARNING::
510
511
This class does not perform any checks of correctness of input. Use
512
:func:`ToricVariety` and :func:`AffineToricVariety` to construct toric
513
varieties.
514
515
INPUT:
516
517
- ``fan`` -- :class:`rational polyhedral fan
518
<sage.geometry.fan.RationalPolyhedralFan>`;
519
520
- ``coordinate_names`` -- names of variables, see :func:`normalize_names`
521
for acceptable formats. If ``None``, indexed variable names will be
522
created automatically;
523
524
- ``coordinate_indices`` -- list of integers, indices for indexed
525
variables. If ``None``, the index of each variable will coincide with
526
the index of the corresponding ray of the fan;
527
528
- ``base_field`` -- base field of the toric variety.
529
530
OUTPUT:
531
532
- :class:`toric variety <ToricVariety_field>`.
533
534
TESTS::
535
536
sage: fan = FaceFan(lattice_polytope.octahedron(2))
537
sage: P1xP1 = ToricVariety(fan)
538
"""
539
540
def __init__(self, fan, coordinate_names, coordinate_indices, base_field):
541
r"""
542
See :class:`ToricVariety_field` for documentation.
543
544
TESTS::
545
546
sage: fan = FaceFan(lattice_polytope.octahedron(2))
547
sage: P1xP1 = ToricVariety(fan)
548
"""
549
self._fan = fan
550
super(ToricVariety_field, self).__init__(fan.lattice_dim(),
551
base_field)
552
self._torus_factor_dim = fan.lattice_dim() - fan.dim()
553
coordinate_names = normalize_names(coordinate_names,
554
fan.nrays() + self._torus_factor_dim, DEFAULT_PREFIX,
555
coordinate_indices, return_prefix=True)
556
# Save the prefix for use in resolutions
557
self._coordinate_prefix = coordinate_names.pop()
558
self._assign_names(names=coordinate_names, normalize=False)
559
560
def __cmp__(self, right):
561
r"""
562
Compare ``self`` and ``right``.
563
564
INPUT:
565
566
- ``right`` -- anything.
567
568
OUTPUT:
569
570
- 0 if ``right`` is of the same type as ``self``, their fans are the
571
same, names of variables are the same and stored in the same order,
572
and base fields are the same. 1 or -1 otherwise.
573
574
TESTS::
575
576
sage: fan = FaceFan(lattice_polytope.octahedron(2))
577
sage: P1xP1 = ToricVariety(fan)
578
sage: P1xP1a = ToricVariety(fan, "x s y t")
579
sage: P1xP1b = ToricVariety(fan)
580
sage: cmp(P1xP1, P1xP1a)
581
1
582
sage: cmp(P1xP1a, P1xP1)
583
-1
584
sage: cmp(P1xP1, P1xP1b)
585
0
586
sage: P1xP1 is P1xP1b
587
False
588
sage: cmp(P1xP1, 1) * cmp(1, P1xP1)
589
-1
590
"""
591
c = cmp(type(self), type(right))
592
if c:
593
return c
594
return cmp([self.fan(),
595
self.variable_names(),
596
self.base_ring()],
597
[right.fan(),
598
right.variable_names(),
599
right.base_ring()])
600
601
def _an_element_(self):
602
r"""
603
Construct an element of ``self``.
604
605
This function is needed (in particular) for the test framework.
606
607
OUTPUT:
608
609
- a point of ``self`` with coordinates [1 : 2: ... : n].
610
611
TESTS::
612
613
sage: fan = FaceFan(lattice_polytope.octahedron(2))
614
sage: P1xP1 = ToricVariety(fan)
615
sage: P1xP1._an_element_()
616
[1 : 2 : 3 : 4]
617
"""
618
return self(range(1, self.ngens() + 1))
619
620
def _check_satisfies_equations(self, coordinates):
621
r"""
622
Check if ``coordinates`` define a valid point of ``self``.
623
624
INPUT:
625
626
- ``coordinates`` -- list of elements of the base field of ``self``.
627
628
OUTPUT:
629
630
- ``True`` if ``coordinates`` do define a valid point of ``self``,
631
otherwise a ``TypeError`` or ``ValueError`` exception is raised.
632
633
TESTS::
634
635
sage: fan = FaceFan(lattice_polytope.octahedron(2))
636
sage: P1xP1 = ToricVariety(fan)
637
sage: P1xP1._check_satisfies_equations([1,1,1,1])
638
True
639
sage: P1xP1._check_satisfies_equations([0,0,1,1])
640
True
641
sage: P1xP1._check_satisfies_equations([0,1,0,1])
642
Traceback (most recent call last):
643
...
644
TypeError: coordinates (0, 1, 0, 1)
645
are in the exceptional set!
646
sage: P1xP1._check_satisfies_equations([1,1,1])
647
Traceback (most recent call last):
648
...
649
TypeError: coordinates (1, 1, 1) must have 4 components!
650
sage: P1xP1._check_satisfies_equations(1)
651
Traceback (most recent call last):
652
...
653
TypeError: 1 can not be used as coordinates!
654
Use a list or a tuple.
655
sage: P1xP1._check_satisfies_equations([1,1,1,fan])
656
Traceback (most recent call last):
657
...
658
TypeError: coordinate Rational polyhedral fan
659
in 2-d lattice N is not an element of Rational Field!
660
"""
661
try:
662
coordinates = tuple(coordinates)
663
except TypeError:
664
raise TypeError("%s can not be used as coordinates! "
665
"Use a list or a tuple." % coordinates)
666
n = self.ngens()
667
if len(coordinates) != n:
668
raise TypeError("coordinates %s must have %d components!"
669
% (coordinates, n))
670
base_field = self.base_ring()
671
for coordinate in coordinates:
672
if coordinate not in base_field:
673
raise TypeError("coordinate %s is not an element of %s!"
674
% (coordinate, base_field))
675
zero_positions = set(position
676
for position, coordinate in enumerate(coordinates)
677
if coordinate == 0)
678
if not zero_positions:
679
return True
680
for i in range(n - self._torus_factor_dim, n):
681
if i in zero_positions:
682
raise ValueError("coordinates on the torus factor cannot be "
683
"zero! Got %s" % str(coordinates))
684
if len(zero_positions) == 1:
685
return True
686
fan = self.fan()
687
possible_charts = set(fan._ray_to_cones(zero_positions.pop()))
688
for i in zero_positions:
689
possible_charts.intersection_update(fan._ray_to_cones(i))
690
if possible_charts:
691
return True # All zeros are inside one generating cone
692
raise TypeError("coordinates %s are in the exceptional set!"
693
% str(coordinates)) # Need str, coordinates is a tuple
694
695
def _point_homset(self, *args, **kwds):
696
r"""
697
Construct a Hom-set for ``self``.
698
699
INPUT:
700
701
- same as for
702
:class:`~sage.schemes.generic.homset.SchemeHomset_points_toric_field`.
703
704
OUPUT:
705
706
-
707
:class:`~sage.schemes.generic.homset.SchemeHomset_points_toric_field`.
708
709
TESTS::
710
711
sage: fan = FaceFan(lattice_polytope.octahedron(2))
712
sage: P1xP1 = ToricVariety(fan)
713
sage: P1xP1._point_homset(Spec(QQ), P1xP1)
714
Set of rational points of 2-d toric variety
715
covered by 4 affine patches
716
"""
717
return SchemeHomset_points_toric_field(*args, **kwds)
718
719
def _latex_(self):
720
r"""
721
Return a LaTeX representation of ``self``.
722
723
OUTPUT:
724
725
- string.
726
727
TESTS::
728
729
sage: fan = FaceFan(lattice_polytope.octahedron(2))
730
sage: P1xP1 = ToricVariety(fan)
731
sage: P1xP1._latex_()
732
'\\mathbb{X}_{\\Sigma^{2}}'
733
"""
734
return r"\mathbb{X}_{%s}" % latex(self.fan())
735
736
def _latex_generic_point(self, coordinates=None):
737
"""
738
Return a LaTeX representation of a point of ``self``.
739
740
INPUT:
741
742
- ``coordinates`` -- list of coordinates of a point of ``self``.
743
If not given, names of coordinates of ``self`` will be used.
744
745
OUTPUT:
746
747
- string.
748
749
EXAMPLES::
750
751
sage: fan = FaceFan(lattice_polytope.octahedron(2))
752
sage: P1xP1 = ToricVariety(fan)
753
sage: P1xP1._latex_generic_point()
754
'\\left[z_{0} : z_{1} : z_{2} : z_{3}\\right]'
755
sage: P1xP1._latex_generic_point([1,2,3,4])
756
'\\left[1 : 2 : 3 : 4\\right]'
757
"""
758
if coordinates is None:
759
coordinates = self.gens()
760
return r"\left[%s\right]" % (" : ".join(str(latex(coord))
761
for coord in coordinates))
762
763
def _point(self, *args, **kwds):
764
r"""
765
Construct a point of ``self``.
766
767
INPUT:
768
769
- same as for
770
:class:`~sage.schemes.generic.morphism.SchemeMorphism_point_toric_field`.
771
772
OUPUT:
773
774
:class:`~sage.schemes.generic.morphism.SchemeMorphism_point_toric_field`.
775
776
TESTS::
777
778
sage: fan = FaceFan(lattice_polytope.octahedron(2))
779
sage: P1xP1 = ToricVariety(fan)
780
sage: P1xP1._point(P1xP1, [1,2,3,4])
781
[1 : 2 : 3 : 4]
782
"""
783
from sage.schemes.toric.morphism import SchemeMorphism_point_toric_field
784
return SchemeMorphism_point_toric_field(*args, **kwds)
785
786
def _homset(self, *args, **kwds):
787
r"""
788
Return the homset between two toric varieties.
789
790
INPUT:
791
792
Same as :class:`sage.schemes.generic.homset.SchemeHomset_generic`.
793
794
OUTPUT:
795
796
A :class:`sage.schemes.toric.homset.SchemeHomset_toric_variety`.
797
798
EXAMPLES::
799
800
sage: P1xP1 = toric_varieties.P1xP1()
801
sage: P1 = toric_varieties.P1()
802
sage: hom_set = P1xP1.Hom(P1); hom_set
803
Set of morphisms
804
From: 2-d CPR-Fano toric variety covered by 4 affine patches
805
To: 1-d CPR-Fano toric variety covered by 2 affine patches
806
sage: type(hom_set)
807
<class 'sage.schemes.toric.homset.SchemeHomset_toric_variety_with_category'>
808
809
This is also the Hom-set for algebraic subschemes of toric varieties::
810
811
sage: P1xP1.inject_variables()
812
Defining s, t, x, y
813
sage: P1 = P1xP1.subscheme(s-t)
814
sage: hom_set = P1xP1.Hom(P1)
815
sage: hom_set([s,s,x,y])
816
Scheme morphism:
817
From: 2-d CPR-Fano toric variety covered by 4 affine patches
818
To: Closed subscheme of 2-d CPR-Fano toric variety covered by 4 affine patches defined by:
819
s - t
820
Defn: Defined on coordinates by sending [s : t : x : y] to
821
[s : s : x : y]
822
823
sage: hom_set = P1.Hom(P1)
824
sage: hom_set([s,s,x,y])
825
Scheme endomorphism of Closed subscheme of 2-d CPR-Fano toric
826
variety covered by 4 affine patches defined by:
827
s - t
828
Defn: Defined on coordinates by sending [s : t : x : y] to
829
[t : t : x : y]
830
"""
831
from sage.schemes.toric.homset import SchemeHomset_toric_variety
832
return SchemeHomset_toric_variety(*args, **kwds)
833
834
def _repr_(self):
835
r"""
836
Return a string representation of ``self``.
837
838
OUTPUT:
839
840
- string.
841
842
TESTS::
843
844
sage: fan = FaceFan(lattice_polytope.octahedron(2))
845
sage: P1xP1 = ToricVariety(fan)
846
sage: P1xP1._repr_()
847
'2-d toric variety covered by 4 affine patches'
848
"""
849
result = "%d-d" % self.dimension_relative()
850
if self.fan().ngenerating_cones() == 1:
851
result += " affine toric variety"
852
else:
853
result += (" toric variety covered by %d affine patches"
854
% self.fan().ngenerating_cones())
855
return result
856
857
def _repr_generic_point(self, coordinates=None):
858
r"""
859
Return a string representation of a point of ``self``.
860
861
INPUT:
862
863
- ``coordinates`` -- list of coordinates of a point of ``self``.
864
If not given, names of coordinates of ``self`` will be used.
865
866
OUTPUT:
867
868
- string.
869
870
EXAMPLES::
871
872
sage: fan = FaceFan(lattice_polytope.octahedron(2))
873
sage: P1xP1 = ToricVariety(fan)
874
sage: P1xP1._repr_generic_point()
875
'[z0 : z1 : z2 : z3]'
876
sage: P1xP1._repr_generic_point([1,2,3,4])
877
'[1 : 2 : 3 : 4]'
878
"""
879
if coordinates is None:
880
coordinates = self.gens()
881
return "[%s]" % (" : ".join(str(coord) for coord in coordinates))
882
883
def _validate(self, polynomials):
884
"""
885
Check if ``polynomials`` define valid functions on ``self``.
886
887
Since this is a toric variety, polynomials must be homogeneous in the
888
total coordinate ring of ``self``.
889
890
INPUT:
891
892
- ``polynomials`` -- list of polynomials in the coordinate ring of
893
``self`` (this function does not perform any conversions).
894
895
OUTPUT:
896
897
- ``polynomials`` (the input parameter without any modifications) if
898
``polynomials`` do define valid polynomial functions on ``self``,
899
otherwise a ``ValueError`` exception is raised.
900
901
TESTS:
902
903
We will use the product of two projective lines with coordinates
904
`(x, y)` for one and `(s, t)` for the other::
905
906
sage: fan = FaceFan(lattice_polytope.octahedron(2))
907
sage: fan.ray_matrix()
908
[ 1 0 -1 0]
909
[ 0 1 0 -1]
910
sage: P1xP1 = ToricVariety(fan, "x s y t")
911
sage: P1xP1.inject_variables()
912
Defining x, s, y, t
913
sage: P1xP1._validate([x - y, x*s + y*t])
914
[x - y, x*s + y*t]
915
sage: P1xP1._validate([x + s])
916
Traceback (most recent call last):
917
...
918
ValueError: x + s is not homogeneous on
919
2-d toric variety covered by 4 affine patches!
920
"""
921
for p in polynomials:
922
if not self.is_homogeneous(p):
923
raise ValueError("%s is not homogeneous on %s!" % (p, self))
924
return polynomials
925
926
def affine_patch(self, i):
927
r"""
928
Return the ``i``-th affine patch of ``self``.
929
930
INPUT:
931
932
- ``i`` -- integer, index of a generating cone of the fan of ``self``.
933
934
OUTPUT:
935
936
- affine :class:`toric variety <ToricVariety_field>` corresponding to
937
the ``i``-th generating cone of the fan of ``self``.
938
939
The result is cached, so the ``i``-th patch is always the same object
940
in memory.
941
942
See also :meth:`affine_algebraic_patch`, which expresses the
943
patches as subvarieties of affine space instead.
944
945
EXAMPLES::
946
947
sage: fan = FaceFan(lattice_polytope.octahedron(2))
948
sage: P1xP1 = ToricVariety(fan, "x s y t")
949
sage: patch0 = P1xP1.affine_patch(0)
950
sage: patch0
951
2-d affine toric variety
952
sage: patch0.embedding_morphism()
953
Scheme morphism:
954
From: 2-d affine toric variety
955
To: 2-d toric variety covered by 4 affine patches
956
Defn: Defined on coordinates by sending [x : t] to
957
[x : 1 : 1 : t]
958
sage: patch1 = P1xP1.affine_patch(1)
959
sage: patch1.embedding_morphism()
960
Scheme morphism:
961
From: 2-d affine toric variety
962
To: 2-d toric variety covered by 4 affine patches
963
Defn: Defined on coordinates by sending [y : t] to
964
[1 : 1 : y : t]
965
sage: patch1 is P1xP1.affine_patch(1)
966
True
967
"""
968
i = int(i) # implicit type checking
969
try:
970
return self._affine_patches[i]
971
except AttributeError:
972
self._affine_patches = dict()
973
except KeyError:
974
pass
975
cone = self.fan().generating_cone(i)
976
names = self.variable_names()
977
# Number of "honest fan coordinates"
978
n = self.fan().nrays()
979
# Number of "torus factor coordinates"
980
t = self._torus_factor_dim
981
names = ([names[ray] for ray in cone.ambient_ray_indices()]
982
+ list(names[n:]))
983
patch = AffineToricVariety(cone, names, base_field=self.base_ring())
984
embedding_coordinates = [1] * n
985
for k, ray in enumerate(cone.ambient_ray_indices()):
986
embedding_coordinates[ray] = patch.gen(k)
987
if t > 0: # Passing "-0" gives unintended result
988
embedding_coordinates.extend(patch.gens()[-t:])
989
patch._embedding_morphism = patch.hom(embedding_coordinates, self)
990
self._affine_patches[i] = patch
991
return patch
992
993
def change_ring(self, F):
994
r"""
995
Return a toric variety over ``F`` and otherwise the same as ``self``.
996
997
INPUT:
998
999
- ``F`` -- field.
1000
1001
OUTPUT:
1002
1003
- :class:`toric variety <ToricVariety_field>` over ``F``.
1004
1005
.. NOTE::
1006
1007
There is no need to have any relation between ``F`` and the base
1008
field of ``self``. If you do want to have such a relation, use
1009
:meth:`base_extend` instead.
1010
1011
EXAMPLES::
1012
1013
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1014
sage: P1xP1 = ToricVariety(fan)
1015
sage: P1xP1.base_ring()
1016
Rational Field
1017
sage: P1xP1_RR = P1xP1.change_ring(RR)
1018
sage: P1xP1_RR.base_ring()
1019
Real Field with 53 bits of precision
1020
sage: P1xP1_QQ = P1xP1_RR.change_ring(QQ)
1021
sage: P1xP1_QQ.base_ring()
1022
Rational Field
1023
sage: P1xP1_RR.base_extend(QQ)
1024
Traceback (most recent call last):
1025
...
1026
ValueError: no natural map from the base ring
1027
(=Real Field with 53 bits of precision)
1028
to R (=Rational Field)!
1029
"""
1030
if self.base_ring() == F:
1031
return self
1032
else:
1033
return ToricVariety(self.fan(), self.variable_names(),
1034
base_field=F)
1035
1036
def coordinate_ring(self):
1037
r"""
1038
Return the coordinate ring of ``self``.
1039
1040
For toric varieties this is the homogeneous coordinate ring (a.k.a.
1041
Cox's ring and total ring).
1042
1043
OUTPUT:
1044
1045
- polynomial ring.
1046
1047
EXAMPLES::
1048
1049
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1050
sage: P1xP1 = ToricVariety(fan)
1051
sage: P1xP1.coordinate_ring()
1052
Multivariate Polynomial Ring in z0, z1, z2, z3
1053
over Rational Field
1054
1055
TESTS::
1056
1057
sage: R = toric_varieties.A1().coordinate_ring(); R
1058
Multivariate Polynomial Ring in z over Rational Field
1059
sage: type(R)
1060
<type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'>
1061
"""
1062
if "_coordinate_ring" not in self.__dict__:
1063
names = self.variable_names()
1064
self._coordinate_ring = PolynomialRing(self.base_ring(), len(names), names)
1065
return self._coordinate_ring
1066
1067
def embedding_morphism(self):
1068
r"""
1069
Return the default embedding morphism of ``self``.
1070
1071
Such a morphism is always defined for an affine patch of a toric
1072
variety (which is also a toric varieties itself).
1073
1074
OUTPUT:
1075
1076
- :class:`scheme morphism
1077
<sage.schemes.generic.morphism.SchemeMorphism_polynomial_toric_variety>`
1078
if the default embedding morphism was defined for ``self``,
1079
otherwise a ``ValueError`` exception is raised.
1080
1081
EXAMPLES::
1082
1083
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1084
sage: P1xP1 = ToricVariety(fan, "x s y t")
1085
sage: P1xP1.embedding_morphism()
1086
Traceback (most recent call last):
1087
...
1088
ValueError: no default embedding was
1089
defined for this toric variety!
1090
sage: patch = P1xP1.affine_patch(0)
1091
sage: patch
1092
2-d affine toric variety
1093
sage: patch.embedding_morphism()
1094
Scheme morphism:
1095
From: 2-d affine toric variety
1096
To: 2-d toric variety covered by 4 affine patches
1097
Defn: Defined on coordinates by sending [x : t] to
1098
[x : 1 : 1 : t]
1099
"""
1100
try:
1101
return self._embedding_morphism
1102
except AttributeError:
1103
raise ValueError("no default embedding was defined for this "
1104
"toric variety!")
1105
1106
def fan(self, dim=None, codim=None):
1107
r"""
1108
Return the underlying fan of ``self`` or its cones.
1109
1110
INPUT:
1111
1112
- ``dim`` -- dimension of the requested cones;
1113
1114
- ``codim`` -- codimension of the requested cones.
1115
1116
OUTPUT:
1117
1118
- :class:`rational polyhedral fan
1119
<sage.geometry.fan.RationalPolyhedralFan>` if no parameters were
1120
given, :class:`tuple` of :class:`cones
1121
<sage.geometry.cone.ConvexRationalPolyhedralCone>` otherwise.
1122
1123
EXAMPLES::
1124
1125
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1126
sage: P1xP1 = ToricVariety(fan)
1127
sage: P1xP1.fan()
1128
Rational polyhedral fan in 2-d lattice N
1129
sage: P1xP1.fan() is fan
1130
True
1131
sage: P1xP1.fan(1)[0]
1132
1-d cone of Rational polyhedral fan in 2-d lattice N
1133
"""
1134
return self._fan(dim, codim)
1135
1136
def inject_coefficients(self, scope=None, verbose=True):
1137
r"""
1138
Inject generators of the base field of ``self`` into ``scope``.
1139
1140
This function is useful if the base field is the field of rational
1141
functions.
1142
1143
INPUT:
1144
1145
- ``scope`` -- namespace (default: global, not just the scope from
1146
which this function was called);
1147
1148
- ``verbose`` -- if ``True`` (default), names of injected generators
1149
will be printed.
1150
1151
OUTPUT:
1152
1153
- none.
1154
1155
EXAMPLES::
1156
1157
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1158
sage: F = QQ["a, b"].fraction_field()
1159
sage: P1xP1 = ToricVariety(fan, base_field=F)
1160
sage: P1xP1.inject_coefficients()
1161
Defining a, b
1162
1163
We check that we can use names ``a`` and ``b``, Trac #10498 is fixed::
1164
1165
sage: a + b
1166
a + b
1167
sage: a + b in P1xP1.coordinate_ring()
1168
True
1169
"""
1170
if scope is None:
1171
# scope = globals() does not work well, the above doctest fails.
1172
# Instead we "borrow" this code from sage.misc.misc.inject_variable
1173
depth = 0
1174
while True:
1175
scope = sys._getframe(depth).f_globals
1176
if (scope["__name__"] == "__main__"
1177
and scope["__package__"] is None):
1178
break
1179
depth += 1
1180
try:
1181
self.base_ring().inject_variables(scope, verbose)
1182
except AttributeError:
1183
pass
1184
1185
@cached_method
1186
def dimension_singularities(self):
1187
r"""
1188
Return the dimension of the singular set.
1189
1190
OUTPUT:
1191
1192
Integer. The dimension of the singular set of the toric
1193
variety. Often the singular set is a reducible subvariety, and
1194
this method will return the dimension of the
1195
largest-dimensional component.
1196
1197
Returns -1 if the toric variety is smooth.
1198
1199
EXAMPLES::
1200
1201
sage: toric_varieties.P4_11169().dimension_singularities()
1202
1
1203
sage: toric_varieties.Conifold().dimension_singularities()
1204
0
1205
sage: toric_varieties.P2().dimension_singularities()
1206
-1
1207
"""
1208
for codim in range(0,self.dimension()+1):
1209
if any(not cone.is_smooth() for cone in self.fan(codim)):
1210
return self.dimension() - codim
1211
return -1
1212
1213
def is_homogeneous(self, polynomial):
1214
r"""
1215
Check if ``polynomial`` is homogeneous.
1216
1217
The coordinate ring of a toric variety is multigraded by relations
1218
between generating rays of the underlying fan.
1219
1220
INPUT:
1221
1222
- ``polynomial`` -- polynomial in the coordinate ring of ``self`` or
1223
its quotient.
1224
1225
OUTPUT:
1226
1227
- ``True`` if ``polynomial`` is homogeneous and ``False`` otherwise.
1228
1229
EXAMPLES:
1230
1231
We will use the product of two projective lines with coordinates
1232
`(x, y)` for one and `(s, t)` for the other::
1233
1234
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1235
sage: fan.ray_matrix()
1236
[ 1 0 -1 0]
1237
[ 0 1 0 -1]
1238
sage: P1xP1 = ToricVariety(fan, "x s y t")
1239
sage: P1xP1.inject_variables()
1240
Defining x, s, y, t
1241
sage: P1xP1.is_homogeneous(x - y)
1242
True
1243
sage: P1xP1.is_homogeneous(x*s + y*t)
1244
True
1245
sage: P1xP1.is_homogeneous(x - t)
1246
False
1247
sage: P1xP1.is_homogeneous(1)
1248
True
1249
1250
Note that by homogeneous, we mean well-defined with respect to
1251
the homogeneous rescalings of ``self``. So a polynomial that you would
1252
usually not call homogeneous can be homogeneous if there are
1253
no homogeneous rescalings, for example::
1254
1255
sage: A1.<z> = toric_varieties.A1()
1256
sage: A1.is_homogeneous(z^3+z^7)
1257
True
1258
1259
Finally, the degree group is really the Chow group
1260
`A_{d-1}(X)` and can contain torsion. For example, take
1261
`\CC^2/\ZZ_2`. Here, the Chow group is `A_{d-1}(\CC^2/\ZZ_2) =
1262
\ZZ_2` and distinguishes even-degree homogeneous polynomials
1263
from odd-degree homogeneous polynomials::
1264
1265
sage: A2_Z2.<x,y> = toric_varieties.A2_Z2()
1266
sage: A2_Z2.is_homogeneous(x+y+x^3+y^5+x^3*y^4)
1267
True
1268
sage: A2_Z2.is_homogeneous(x^2+x*y+y^4+(x*y)^5+x^4*y^4)
1269
True
1270
sage: A2_Z2.is_homogeneous(x+y^2)
1271
False
1272
"""
1273
if '_homogeneous_degrees_group' not in self.__dict__:
1274
fan = self.fan()
1275
from sage.modules.free_module import FreeModule
1276
degrees_group = FreeModule(ZZ, fan.nrays()).quotient(fan.ray_matrix().rows())
1277
self._homogeneous_degrees_group = degrees_group
1278
degrees_group = self._homogeneous_degrees_group
1279
S = self.coordinate_ring()
1280
try:
1281
polynomial = S(polynomial)
1282
except TypeError:
1283
# Then it should be in the quotient corresponding to a subscheme
1284
polynomial = S(polynomial.lift())
1285
monomials = polynomial.monomials()
1286
if not monomials:
1287
return True
1288
degree = degrees_group(vector(ZZ,monomials[0].degrees()))
1289
for monomial in monomials:
1290
if degrees_group(vector(ZZ,monomial.degrees())) != degree:
1291
return False
1292
return True
1293
1294
def is_isomorphic(self, another):
1295
r"""
1296
Check if ``self`` is isomorphic to ``another``.
1297
1298
INPUT:
1299
1300
- ``another`` - :class:`toric variety <ToricVariety_field>`.
1301
1302
OUTPUT:
1303
1304
- ``True`` if ``self`` and ``another`` are isomorphic,
1305
``False`` otherwise.
1306
1307
EXAMPLES::
1308
1309
sage: fan1 = FaceFan(lattice_polytope.octahedron(2))
1310
sage: TV1 = ToricVariety(fan1)
1311
sage: fan2 = NormalFan(lattice_polytope.octahedron(2))
1312
sage: TV2 = ToricVariety(fan2)
1313
1314
Only the most trivial case is implemented so far::
1315
1316
sage: TV1.is_isomorphic(TV1)
1317
True
1318
sage: TV1.is_isomorphic(TV2)
1319
Traceback (most recent call last):
1320
...
1321
NotImplementedError:
1322
isomorphism check is not yet implemented!
1323
"""
1324
if self is another:
1325
return True
1326
if not is_ToricVariety(another):
1327
raise TypeError(
1328
"only another toric variety can be checked for isomorphism! "
1329
"Got %s" % another)
1330
raise NotImplementedError("isomorphism check is not yet implemented!")
1331
1332
def is_affine(self):
1333
r"""
1334
Check if ``self`` is an affine toric variety.
1335
1336
An affine toric variety is a toric variety whose fan is the
1337
face lattice of a single cone. See also
1338
:func:`AffineToricVariety`.
1339
1340
OUTPUT:
1341
1342
Boolean.
1343
1344
EXMAMPLES:
1345
1346
sage: toric_varieties.A2().is_affine()
1347
True
1348
sage: toric_varieties.P1xA1().is_affine()
1349
False
1350
"""
1351
return self.fan().ngenerating_cones() == 1
1352
1353
def is_complete(self):
1354
r"""
1355
Check if ``self`` is complete.
1356
1357
OUTPUT:
1358
1359
- ``True`` if ``self`` is complete and ``False`` otherwise.
1360
1361
EXAMPLES::
1362
1363
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1364
sage: P1xP1 = ToricVariety(fan)
1365
sage: P1xP1.is_complete()
1366
True
1367
sage: P1xP1.affine_patch(0).is_complete()
1368
False
1369
"""
1370
return self.fan().is_complete()
1371
1372
def is_orbifold(self):
1373
r"""
1374
Check if ``self`` has only quotient singularities.
1375
1376
A toric variety with at most orbifold singularities (in this
1377
sense) is often called a simplicial toric variety. In this
1378
package, we generally try to avoid this term since it mixes up
1379
differential geometry and cone terminology.
1380
1381
OUTPUT:
1382
1383
- ``True`` if ``self`` has at most quotient singularities by
1384
finite groups, ``False`` otherwise.
1385
1386
EXAMPLES::
1387
1388
sage: fan1 = FaceFan(lattice_polytope.octahedron(2))
1389
sage: P1xP1 = ToricVariety(fan1)
1390
sage: P1xP1.is_orbifold()
1391
True
1392
sage: fan2 = NormalFan(lattice_polytope.octahedron(3))
1393
sage: TV = ToricVariety(fan2)
1394
sage: TV.is_orbifold()
1395
False
1396
"""
1397
return self.fan().is_simplicial()
1398
1399
def is_smooth(self):
1400
r"""
1401
Check if ``self`` is smooth.
1402
1403
OUTPUT:
1404
1405
- ``True`` if ``self`` is smooth and ``False`` otherwise.
1406
1407
EXAMPLES::
1408
1409
sage: diamond = lattice_polytope.octahedron(2)
1410
sage: fan1 = FaceFan(diamond)
1411
sage: P1xP1 = ToricVariety(fan1)
1412
sage: P1xP1.is_smooth()
1413
True
1414
sage: fan2 = NormalFan(lattice_polytope.octahedron(2))
1415
sage: TV = ToricVariety(fan2)
1416
sage: TV.is_smooth()
1417
False
1418
"""
1419
return self.fan().is_smooth()
1420
1421
def Kaehler_cone(self):
1422
r"""
1423
Return the closure of the Kähler cone of ``self``.
1424
1425
OUTPUT:
1426
1427
- :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`.
1428
1429
.. NOTE::
1430
1431
This cone sits in the rational divisor class group of ``self`` and
1432
the choice of coordinates agrees with
1433
:meth:`rational_class_group`.
1434
1435
EXAMPLES::
1436
1437
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1438
sage: P1xP1 = ToricVariety(fan)
1439
sage: Kc = P1xP1.Kaehler_cone()
1440
sage: Kc
1441
2-d cone in 2-d lattice
1442
sage: Kc.rays()
1443
(Divisor class [0, 1], Divisor class [1, 0])
1444
sage: [ divisor_class.lift() for divisor_class in Kc.rays() ]
1445
[V(z1), V(z0)]
1446
sage: Kc.lattice()
1447
The toric rational divisor class group
1448
of a 2-d toric variety covered by 4 affine patches
1449
"""
1450
if "_Kaehler_cone" not in self.__dict__:
1451
fan = self.fan()
1452
GT = fan.Gale_transform().columns()
1453
n = fan.nrays()
1454
K = None
1455
for cone in fan:
1456
sigma = Cone([GT[i] for i in range(n)
1457
if i not in cone.ambient_ray_indices()],
1458
lattice = self.rational_class_group())
1459
K = K.intersection(sigma) if K is not None else sigma
1460
self._Kaehler_cone = K
1461
return self._Kaehler_cone
1462
1463
def Mori_cone(self):
1464
"""
1465
Returns the Mori cone of ``self``.
1466
1467
OUTPUT:
1468
1469
- :class:`cone <sage.geometry.cone.ConvexRationalPolyhedralCone>`.
1470
1471
.. NOTE::
1472
1473
* The Mori cone is dual to the Kähler cone.
1474
1475
* We think of the Mori cone as living inside the row span of the
1476
Gale transform matrix (computed by
1477
``self.fan().Gale_transform()``).
1478
1479
* The points in the Mori cone are the effective curves in the
1480
variety.
1481
1482
* The ``i``-th entry in each Mori vector is the intersection
1483
number of the curve corresponding to the generator of the
1484
``i``-th ray of the fan with the corresponding divisor class.
1485
The very last entry is associated to the orgin of the fan
1486
lattice.
1487
1488
* The Mori vectors are also known as the gauged linear sigma model
1489
charge vectors.
1490
1491
EXAMPLES::
1492
1493
sage: P4_11169 = toric_varieties.P4_11169_resolved()
1494
sage: P4_11169.Mori_cone()
1495
2-d cone in 7-d lattice
1496
sage: P4_11169.Mori_cone().rays()
1497
((0, 0, 1, 1, 1, -3, 0), (3, 2, 0, 0, 0, 1, -6))
1498
"""
1499
if "_Mori_cone" not in self.__dict__:
1500
# Ideally, self.Kaehler_cone().dual() should be it, but
1501
# so far this is not the case.
1502
rays = (ray * self._fan.Gale_transform()
1503
for ray in self.Kaehler_cone().dual().rays())
1504
self._Mori_cone = Cone(rays, lattice=ZZ**(self._fan.nrays()+1))
1505
return self._Mori_cone
1506
1507
def plot(self, **options):
1508
r"""
1509
Plot ``self``, i.e. the corresponding fan.
1510
1511
INPUT:
1512
1513
- any options for toric plots (see :func:`toric_plotter.options
1514
<sage.geometry.toric_plotter.options>`), none are mandatory.
1515
1516
OUTPUT:
1517
1518
- a plot.
1519
1520
.. NOTE::
1521
1522
The difference between ``X.plot()`` and ``X.fan().plot()`` is that
1523
in the first case default ray labels correspond to variables of
1524
``X``.
1525
1526
EXAMPLES::
1527
1528
sage: X = toric_varieties.Cube_deformation(4)
1529
sage: X.plot()
1530
"""
1531
if "ray_label" not in options:
1532
gens = self.coordinate_ring().gens()
1533
if self.fan().lattice().degree() <= 2:
1534
options["ray_label"] = ["$%s$" % latex(z) for z in gens]
1535
else:
1536
options["ray_label"] = [str(z) for z in gens]
1537
return self.fan().plot(**options)
1538
1539
def rational_class_group(self):
1540
r"""
1541
Return the rational divisor class group of ``self``.
1542
1543
Let `X` be a toric variety.
1544
1545
The **Weil divisor class group** `\mathop{Cl}(X)` is a finitely
1546
generated abelian group and can contain torsion. Its rank equals the
1547
number of rays in the fan of `X` minus the dimension of `X`.
1548
1549
The **rational divisor class group** is
1550
`\mathop{Cl}(X) \otimes_\ZZ \QQ` and never includes torsion. If `X` is
1551
*smooth*, this equals the **Picard group** of `X`, whose elements are
1552
the isomorphism classes of line bundles on `X`. The group law (which
1553
we write as addition) is the tensor product of the line bundles. The
1554
Picard group of a toric variety is always torsion-free.
1555
1556
OUTPUT:
1557
1558
- :class:`rational divisor class group
1559
<sage.schemes.toric.divisor.ToricRationalDivisorClassGroup>`.
1560
1561
.. NOTE::
1562
1563
* Coordinates correspond to the rows of
1564
``self.fan().gale_transform()``.
1565
1566
* :meth:`Kaehler_cone` yields a cone in this group.
1567
1568
EXAMPLES::
1569
1570
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1571
sage: P1xP1 = ToricVariety(fan)
1572
sage: P1xP1.rational_class_group()
1573
The toric rational divisor class group
1574
of a 2-d toric variety covered by 4 affine patches
1575
"""
1576
from sage.schemes.toric.divisor import ToricRationalDivisorClassGroup
1577
return ToricRationalDivisorClassGroup(self)
1578
1579
def Chow_group(self, base_ring=ZZ):
1580
r"""
1581
Return the toric Chow group.
1582
1583
INPUT:
1584
1585
- ``base_ring`` -- either ``ZZ`` (default) or ``QQ``. The
1586
coefficient ring of the Chow group.
1587
1588
OUTPUT:
1589
1590
A :class:`sage.schemes.toric.chow_group.ChowGroup_class`
1591
1592
EXAMPLES::
1593
1594
sage: A = toric_varieties.P2().Chow_group(); A
1595
Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches
1596
sage: A.gens()
1597
(( 1 | 0 | 0 ), ( 0 | 1 | 0 ), ( 0 | 0 | 1 ))
1598
"""
1599
from sage.schemes.toric.chow_group import ChowGroup
1600
return ChowGroup(self,base_ring)
1601
1602
def cartesian_product(self, other,
1603
coordinate_names=None, coordinate_indices=None):
1604
r"""
1605
Return the Cartesian product of ``self`` with ``other``.
1606
1607
INPUT:
1608
1609
- ``other`` -- a :class:`toric variety <ToricVariety_field>`;
1610
1611
- ``coordinate_names`` -- names of variables for the coordinate ring,
1612
see :func:`normalize_names` for acceptable formats. If not given,
1613
indexed variable names will be created automatically;
1614
1615
- ``coordinate_indices`` -- list of integers, indices for indexed
1616
variables. If not given, the index of each variable will coincide
1617
with the index of the corresponding ray of the fan.
1618
1619
OUTPUT:
1620
1621
-- a :class:`toric variety <ToricVariety_field>`.
1622
1623
EXAMPLES::
1624
1625
sage: P1 = ToricVariety(Fan([Cone([(1,)]), Cone([(-1,)])]))
1626
sage: P1xP1 = P1.cartesian_product(P1); P1xP1
1627
2-d toric variety covered by 4 affine patches
1628
sage: P1xP1.fan().rays()
1629
(N+N(-1, 0), N+N(1, 0), N+N(0, -1), N+N(0, 1))
1630
"""
1631
return ToricVariety(self.fan().cartesian_product(other.fan()),
1632
coordinate_names, coordinate_indices,
1633
base_field=self.base_ring())
1634
1635
def resolve(self, **kwds):
1636
r"""
1637
Construct a toric variety whose fan subdivides the fan of ``self``.
1638
1639
The name of this function reflects the fact that usually such
1640
subdivisions are done for resolving singularities of the original
1641
variety.
1642
1643
INPUT:
1644
1645
This function accepts only keyword arguments, none of which are
1646
mandatory.
1647
1648
- ``coordinate_names`` -- names for coordinates of the new variety. If
1649
not given, will be constructed from the coordinate names of ``self``
1650
and necessary indexed ones. See :func:`normalize_names` for the
1651
description of acceptable formats;
1652
1653
- ``coordinate_indices`` -- coordinate indices which should be used
1654
for indexed variables of the new variety;
1655
1656
- all other arguments will be passed to
1657
:meth:`~sage.geometry.fan.RationalPolyhedralFan.subdivide` method of
1658
the underlying :class:`rational polyhedral fan
1659
<sage.geometry.fan.RationalPolyhedralFan>`, see its documentation
1660
for the available options.
1661
1662
OUTPUT:
1663
1664
- :class:`toric variety <ToricVariety_field>`.
1665
1666
EXAMPLES:
1667
1668
First we will "manually" resolve a simple orbifold singularity::
1669
1670
sage: cone = Cone([(1,1), (-1,1)])
1671
sage: fan = Fan([cone])
1672
sage: TV = ToricVariety(fan)
1673
sage: TV.is_smooth()
1674
False
1675
sage: TV_res = TV.resolve(new_rays=[(0,1)])
1676
sage: TV_res.is_smooth()
1677
True
1678
sage: TV_res.fan().ray_matrix()
1679
[ 1 -1 0]
1680
[ 1 1 1]
1681
sage: [cone.ambient_ray_indices() for cone in TV_res.fan()]
1682
[(0, 2), (1, 2)]
1683
1684
Now let's "automatically" partially resolve a more complicated fan::
1685
1686
sage: fan = NormalFan(lattice_polytope.octahedron(3))
1687
sage: TV = ToricVariety(fan)
1688
sage: TV.is_smooth()
1689
False
1690
sage: TV.is_orbifold()
1691
False
1692
sage: TV.fan().nrays()
1693
8
1694
sage: TV.fan().ngenerating_cones()
1695
6
1696
sage: TV_res = TV.resolve(make_simplicial=True)
1697
sage: TV_res.is_smooth()
1698
False
1699
sage: TV_res.is_orbifold()
1700
True
1701
sage: TV_res.fan().nrays()
1702
8
1703
sage: TV_res.fan().ngenerating_cones()
1704
12
1705
sage: TV.gens()
1706
(z0, z1, z2, z3, z4, z5, z6, z7)
1707
sage: TV_res.gens()
1708
(z0, z1, z2, z3, z4, z5, z6, z7)
1709
sage: TV_res = TV.resolve(coordinate_names="x+",
1710
... make_simplicial=True)
1711
sage: TV_res.gens()
1712
(x0, x1, x2, x3, x4, x5, x6, x7)
1713
"""
1714
# If you are changing this function, check out resolve in Fano toric
1715
# varieties to see if it should be changed too
1716
#
1717
# Currently the resolution of fans works for full-dimensional ones
1718
# only, so there is no point to deal with the general case here, since
1719
# we will not be able to check that it works.
1720
coordinate_names = kwds.pop("coordinate_names", None)
1721
coordinate_indices = kwds.pop("coordinate_indices", None)
1722
fan = self.fan()
1723
if fan.dim() != fan.lattice_dim():
1724
raise NotImplementedError("resolution of toric varieties with "
1725
"torus factors is not yet implemented!")
1726
# When it is implemented, should be careful with the torus factor
1727
rfan = fan.subdivide(**kwds)
1728
if coordinate_names is None:
1729
coordinate_names = list(self.variable_names())
1730
if coordinate_indices is None:
1731
coordinate_indices = range(fan.nrays(), rfan.nrays())
1732
else:
1733
coordinate_indices = coordinate_indices[fan.nrays():]
1734
coordinate_names.extend(normalize_names(
1735
ngens=rfan.nrays() - fan.nrays(),
1736
indices=coordinate_indices,
1737
prefix=self._coordinate_prefix))
1738
coordinate_names.append(self._coordinate_prefix + "+")
1739
resolution = ToricVariety(rfan, coordinate_names=coordinate_names,
1740
coordinate_indices=coordinate_indices,
1741
base_field=self.base_ring())
1742
R = self.coordinate_ring()
1743
R_res = resolution.coordinate_ring()
1744
resolution_map = resolution.hom(R.hom(R_res.gens()[:R.ngens()]), self)
1745
resolution._resolution_map = resolution_map
1746
# The above map does not have (yet) public methods to access it.
1747
# While this map is defined correctly, base classes of schemes and
1748
# morphisms do not treat it as they should. The plan is to fix this
1749
# situation soon and to be able to use this map!
1750
return resolution
1751
1752
def resolve_to_orbifold(self, **kwds):
1753
r"""
1754
Construct an orbifold whose fan subdivides the fan of ``self``.
1755
1756
It is a synonym for :meth:`resolve` with ``make_simplicial=True``
1757
option.
1758
1759
INPUT:
1760
1761
- this function accepts only keyword arguments. See :meth:`resolve`
1762
for documentation.
1763
1764
OUTPUT:
1765
1766
- :class:`toric variety <ToricVariety_field>`.
1767
1768
EXAMPLES::
1769
1770
sage: fan = NormalFan(lattice_polytope.octahedron(3))
1771
sage: TV = ToricVariety(fan)
1772
sage: TV.is_orbifold()
1773
False
1774
sage: TV.fan().nrays()
1775
8
1776
sage: TV.fan().ngenerating_cones()
1777
6
1778
sage: TV_res = TV.resolve_to_orbifold()
1779
sage: TV_res.is_orbifold()
1780
True
1781
sage: TV_res.fan().nrays()
1782
8
1783
sage: TV_res.fan().ngenerating_cones()
1784
12
1785
"""
1786
return self.resolve(make_simplicial=True, **kwds)
1787
1788
def subscheme(self, polynomials):
1789
r"""
1790
Return the subscheme of ``self`` defined by ``polynomials``.
1791
1792
INPUT:
1793
1794
- ``polynomials`` -- list of polynomials in the coordinate ring of
1795
``self``.
1796
1797
OUTPUT:
1798
1799
- :class:`subscheme of a toric variety
1800
<sage.schemes.genreric.algebraic_scheme.AlgebraicScheme_subscheme_toric>`.
1801
1802
EXAMPLES:
1803
1804
We will construct a subscheme of the product of two projective lines
1805
with coordinates `(x, y)` for one and `(s, t)` for the other::
1806
1807
sage: fan = FaceFan(lattice_polytope.octahedron(2))
1808
sage: fan.ray_matrix()
1809
[ 1 0 -1 0]
1810
[ 0 1 0 -1]
1811
sage: P1xP1 = ToricVariety(fan, "x s y t")
1812
sage: P1xP1.inject_variables()
1813
Defining x, s, y, t
1814
sage: X = P1xP1.subscheme([x*s + y*t, x^3+y^3])
1815
sage: X
1816
Closed subscheme of 2-d toric variety
1817
covered by 4 affine patches defined by:
1818
x*s + y*t,
1819
x^3 + y^3
1820
sage: X.defining_polynomials()
1821
(x*s + y*t, x^3 + y^3)
1822
sage: X.defining_ideal()
1823
Ideal (x*s + y*t, x^3 + y^3)
1824
of Multivariate Polynomial Ring in x, s, y, t
1825
over Rational Field
1826
sage: X.base_ring()
1827
Rational Field
1828
sage: X.base_scheme()
1829
Spectrum of Rational Field
1830
sage: X.structure_morphism()
1831
Scheme morphism:
1832
From: Closed subscheme of
1833
2-d toric variety covered by 4 affine patches defined by:
1834
x*s + y*t,
1835
x^3 + y^3
1836
To: Spectrum of Rational Field
1837
Defn: Structure map
1838
"""
1839
from sage.schemes.generic.algebraic_scheme import \
1840
AlgebraicScheme_subscheme_toric, AlgebraicScheme_subscheme_affine_toric
1841
if self.is_affine():
1842
return AlgebraicScheme_subscheme_affine_toric(self, polynomials)
1843
else:
1844
return AlgebraicScheme_subscheme_toric(self, polynomials)
1845
1846
def Stanley_Reisner_ideal(self):
1847
"""
1848
Return the Stanley-Reisner ideal.
1849
1850
OUTPUT:
1851
1852
- The Stanley-Reisner ideal in the polynomial ring over
1853
`\QQ` generated by the homogeneous coordinates.
1854
1855
EXAMPLES::
1856
1857
sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)])
1858
sage: X = ToricVariety(fan, coordinate_names='A B C D E', base_field=GF(5))
1859
sage: SR = X.Stanley_Reisner_ideal(); SR
1860
Ideal (A*E, C*D, A*B*C, B*D*E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field
1861
"""
1862
if "_SR" not in self.__dict__:
1863
R = PolynomialRing(QQ, self.variable_names())
1864
self._SR = self._fan.Stanley_Reisner_ideal(R)
1865
return self._SR
1866
1867
def linear_equivalence_ideal(self):
1868
"""
1869
Return the ideal generated by linear relations
1870
1871
OUTPUT:
1872
1873
- The ideal generated by the linear relations of the rays in
1874
the polynomial ring over `\QQ` generated by the homogeneous
1875
coordinates.
1876
1877
EXAMPLES::
1878
1879
sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)])
1880
sage: X = ToricVariety(fan, coordinate_names='A B C D E', base_field=GF(5))
1881
sage: lin = X.linear_equivalence_ideal(); lin
1882
Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field
1883
"""
1884
if "_linear_equivalence_ideal" not in self.__dict__:
1885
R = PolynomialRing(QQ, self.variable_names())
1886
self._linear_equivalence_ideal = self._fan.linear_equivalence_ideal(R)
1887
return self._linear_equivalence_ideal
1888
1889
def cohomology_ring(self):
1890
r"""
1891
Return the cohomology ring of the toric variety.
1892
1893
OUTPUT:
1894
1895
- If the toric variety is is over `\CC` and has at most finite
1896
orbifold singularities: `H^\bullet(X,\QQ)` as a polynomial
1897
quotient ring.
1898
1899
- Other cases are not handled yet.
1900
1901
.. NOTE::
1902
1903
- Toric varieties over any field of characteristic 0 are
1904
treated as if they were varieties over `\CC`.
1905
1906
- The integral cohomology of smooth toric varieties is
1907
torsion-free, so in this case there is no loss of
1908
information when going to rational coefficients.
1909
1910
- ``self.cohomology_ring().gen(i)`` is the divisor class corresponding to
1911
the ``i``-th ray of the fan.
1912
1913
EXAMPLES::
1914
1915
sage: X = toric_varieties.dP6()
1916
sage: X.cohomology_ring()
1917
Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 6 affine patches
1918
sage: X.cohomology_ring().defining_ideal()
1919
Ideal (-u - y + z + w, x - y - v + w, x*y, x*v, x*z, u*v, u*z, u*w, y*z, y*w, v*w) of Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field
1920
sage: X.cohomology_ring().defining_ideal().ring()
1921
Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field
1922
sage: X.variable_names()
1923
('x', 'u', 'y', 'v', 'z', 'w')
1924
sage: X.cohomology_ring().gens()
1925
([y + v - w], [-y + z + w], [y], [v], [z], [w])
1926
"""
1927
if "_cohomology_ring" not in self.__dict__:
1928
if self.base_ring().characteristic()>0:
1929
raise NotImplementedError('Only characteristic 0 base fields '
1930
'are implemented.')
1931
self._cohomology_ring = CohomologyRing(self)
1932
return self._cohomology_ring
1933
1934
def cohomology_basis(self, d=None):
1935
r"""
1936
Return a basis for the cohomology of the toric variety.
1937
1938
INPUT:
1939
1940
- ``d`` (optional) -- integer.
1941
1942
OUTPUT:
1943
1944
- Without the optional argument, a list whose d-th entry is a
1945
basis for `H^{2d}(X,\QQ)`
1946
1947
- If the argument is an integer ``d``, returns basis for
1948
`H^{2d}(X,\QQ)`
1949
1950
EXAMPLES::
1951
1952
sage: X = toric_varieties.dP8()
1953
sage: X.cohomology_basis()
1954
(([1],), ([z], [y]), ([y*z],))
1955
sage: X.cohomology_basis(1)
1956
([z], [y])
1957
sage: X.cohomology_basis(dimension(X))[0] == X.volume_class()
1958
True
1959
"""
1960
if d!=None:
1961
return self.cohomology_basis()[d]
1962
1963
try:
1964
return self._cohomology_basis
1965
except AttributeError:
1966
pass
1967
H = self.cohomology_ring()
1968
# Make an empty list for each d-piece
1969
basis = [[] for d in range(self.dimension() + 1)]
1970
# Distribute basis elements into d-pieces
1971
for x in H.defining_ideal().normal_basis():
1972
basis[x.total_degree()].append(x)
1973
# Convert list of lists of polynomials to
1974
# tuple of tuples of cohomology classes
1975
basis = tuple(tuple(H(x) for x in dbasis)
1976
for dbasis in basis)
1977
self._cohomology_basis = basis
1978
return self._cohomology_basis
1979
1980
def volume_class(self):
1981
r"""
1982
Return the cohomology class of the volume form on the toric
1983
variety.
1984
1985
Note that we are using cohomology with compact supports. If
1986
the variety is non-compact this is dual to homology without
1987
any support condition. In particular, for non-compact
1988
varieties the volume form `\mathrm{dVol}=\wedge_i(dx_i \wedge
1989
dy_i)` does not define a (non-zero) cohomology class.
1990
1991
OUTPUT:
1992
1993
A :class:`CohomologyClass`. If it exists, it is the class of
1994
the (properly normalized) volume form, that is, it is the
1995
Poincare dual of a single point. If it does not exist, a
1996
``ValueError`` is raised.
1997
1998
EXAMPLES::
1999
2000
sage: P2 = toric_varieties.P2()
2001
sage: P2.volume_class()
2002
[z^2]
2003
2004
sage: A2_Z2 = toric_varieties.A2_Z2()
2005
sage: A2_Z2.volume_class()
2006
Traceback (most recent call last):
2007
...
2008
ValueError: Volume class does not exist.
2009
2010
If none of the maximal cones is smooth things get more
2011
tricky. In this case no torus-fixed point is smooth. If we
2012
want to count an ordinary point as `1`, then a `G`-orbifold
2013
point needs to count as `\frac{1}{|G|}`. For example, take
2014
`\mathbb{P}^1\times\mathbb{P}^1` with inhomogeneous
2015
coordinates `(t,y)`. Take the quotient by the action
2016
`(t,y)\mapsto (-t,-y)`. The `\ZZ_2`-invariant Weil divisors
2017
`\{t=0\}` and `\{y=0\}` intersect in a `\ZZ_2`-fixed point, so
2018
they ought to have intersection number `\frac{1}{2}`. This
2019
means that the cohomology class `[t] \cap [y]` should be
2020
`\frac{1}{2}` times the volume class. Note that this is
2021
different from the volume normalization chosen in
2022
[Schubert]_::
2023
2024
sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2()
2025
sage: Dt = P1xP1_Z2.divisor(1); Dt
2026
V(t)
2027
sage: Dy = P1xP1_Z2.divisor(3); Dy
2028
V(y)
2029
sage: P1xP1_Z2.volume_class()
2030
[2*t*y]
2031
2032
sage: HH = P1xP1_Z2.cohomology_ring()
2033
sage: HH(Dt) * HH(Dy) == 1/2 * P1xP1_Z2.volume_class()
2034
True
2035
2036
The fractional coefficients are also necessary to match the
2037
normalization in the rational Chow group for simplicial toric
2038
varieties::
2039
2040
sage: A = P1xP1_Z2.Chow_group(QQ)
2041
sage: A(Dt).intersection_with_divisor(Dy).count_points()
2042
1/2
2043
2044
REFERENCES:
2045
2046
.. [Schubert]
2047
Sheldon Katz and Stein Arild Stromme,
2048
A Maple package for intersection theory and enumerative geometry.
2049
"""
2050
if "_volume_class" not in self.__dict__:
2051
if not self.is_orbifold():
2052
raise NotImplementedError('Cohomology computations are only '
2053
'implemented for orbifolds.')
2054
HH = self.cohomology_ring()
2055
dim = self.dimension_relative()
2056
self._volume_class = HH(self.fan().generating_cone(0)).part_of_degree(dim)
2057
if self._volume_class.is_zero():
2058
raise ValueError, 'Volume class does not exist.'
2059
return self._volume_class
2060
2061
def integrate(self, cohomology_class):
2062
"""
2063
Integrate a cohomology class over the toric variety.
2064
2065
INPUT:
2066
2067
- ``cohomology_class`` -- A cohomology class given as a
2068
polynomial in ``self.cohomology_ring()``
2069
2070
OUTPUT:
2071
2072
The integral of the cohomology class over the variety. The
2073
volume normalization is given by :meth:`volume_class`, that
2074
is, ``self.integrate(self.volume_class())`` is always one (if
2075
the volume class exists).
2076
2077
EXAMPLES::
2078
2079
sage: dP6 = toric_varieties.dP6()
2080
sage: HH = dP6.cohomology_ring()
2081
sage: D = [ HH(c) for c in dP6.fan(dim=1) ]
2082
sage: matrix([ [ D[i]*D[j] for i in range(0,6) ] for j in range(0,6) ])
2083
[ [w^2] [-w^2] [0] [0] [0] [-w^2]]
2084
[[-w^2] [w^2] [-w^2] [0] [0] [0]]
2085
[ [0] [-w^2] [w^2] [-w^2] [0] [0]]
2086
[ [0] [0] [-w^2] [w^2] [-w^2] [0]]
2087
[ [0] [0] [0] [-w^2] [w^2] [-w^2]]
2088
[[-w^2] [0] [0] [0] [-w^2] [w^2]]
2089
sage: matrix([ [ dP6.integrate(D[i]*D[j]) for i in range(0,6) ] for j in range(0,6) ])
2090
[-1 1 0 0 0 1]
2091
[ 1 -1 1 0 0 0]
2092
[ 0 1 -1 1 0 0]
2093
[ 0 0 1 -1 1 0]
2094
[ 0 0 0 1 -1 1]
2095
[ 1 0 0 0 1 -1]
2096
2097
If the toric variety is an orbifold, the intersection numbers
2098
are usually fractional::
2099
2100
sage: P2_123 = toric_varieties.P2_123()
2101
sage: HH = P2_123.cohomology_ring()
2102
sage: D = [ HH(c) for c in P2_123.fan(dim=1) ]
2103
sage: matrix([ [ P2_123.integrate(D[i]*D[j]) for i in range(0,3) ] for j in range(0,3) ])
2104
[2/3 1 1/3]
2105
[ 1 3/2 1/2]
2106
[1/3 1/2 1/6]
2107
sage: A = P2_123.Chow_group(QQ)
2108
sage: matrix([ [ A(P2_123.divisor(i))
2109
... .intersection_with_divisor(P2_123.divisor(j))
2110
... .count_points() for i in range(0,3) ] for j in range(0,3) ])
2111
[2/3 1 1/3]
2112
[ 1 3/2 1/2]
2113
[1/3 1/2 1/6]
2114
"""
2115
assert self.is_complete(), "Can only integrate over compact varieties."
2116
top_form = cohomology_class.part_of_degree(self.dimension())
2117
if top_form.is_zero(): return 0
2118
return top_form.lc() / self.volume_class().lc()
2119
2120
def Chern_class(self, deg=None):
2121
"""
2122
Return Chern classes of the (tangent bundle of the) toric variety.
2123
2124
INPUT:
2125
2126
- ``deg`` -- integer (optional). The degree of the Chern class.
2127
2128
OUTPUT:
2129
2130
- If the degree is specified, the ``deg``-th Chern class.
2131
2132
- If no degree is specified, the total Chern class.
2133
2134
REFERENCES:
2135
2136
..
2137
2138
http://en.wikipedia.org/wiki/Chern_class
2139
2140
EXAMPLES::
2141
2142
sage: X = toric_varieties.dP6()
2143
sage: X.Chern_class()
2144
[-6*w^2 + y + 2*v + 2*z + w + 1]
2145
sage: X.c()
2146
[-6*w^2 + y + 2*v + 2*z + w + 1]
2147
sage: X.c(1)
2148
[y + 2*v + 2*z + w]
2149
sage: X.c(2)
2150
[-6*w^2]
2151
sage: X.integrate( X.c(2) )
2152
6
2153
sage: X.integrate( X.c(2) ) == X.Euler_number()
2154
True
2155
"""
2156
assert self.is_orbifold(), "Requires the toric variety to be an orbifold."
2157
try:
2158
c = self._chern_class
2159
except AttributeError:
2160
c = prod([ 1+self.cohomology_ring().gen(i) for i in range(0,self._fan.nrays()) ])
2161
self._chern_class = c
2162
2163
if deg==None:
2164
return c
2165
else:
2166
return c.part_of_degree(deg)
2167
2168
def Chern_character(self, deg=None):
2169
"""
2170
Return the Chern character (of the tangent bundle) of the toric
2171
variety.
2172
2173
INPUT:
2174
2175
- ``deg`` -- integer (optional). The degree of the Chern
2176
character.
2177
2178
OUTPUT:
2179
2180
- If the degree is specified, the degree-``deg`` part of the
2181
Chern character.
2182
2183
- If no degree is specified, the total Chern character.
2184
2185
REFERENCES:
2186
2187
..
2188
2189
http://en.wikipedia.org/wiki/Chern_character#The_Chern_character
2190
2191
EXAMPLES::
2192
2193
sage: dP6 = toric_varieties.dP6()
2194
sage: dP6.Chern_character()
2195
[3*w^2 + y + 2*v + 2*z + w + 2]
2196
sage: dP6.ch()
2197
[3*w^2 + y + 2*v + 2*z + w + 2]
2198
sage: dP6.ch(1) == dP6.c(1)
2199
True
2200
"""
2201
assert self.is_orbifold(), "Requires the toric variety to be an orbifold."
2202
try:
2203
ch = self._chern_character
2204
except AttributeError:
2205
n_rels = self._fan.nrays() - self.dimension()
2206
ch = sum([ self.cohomology_ring().gen(i).exp()
2207
for i in range(0,self._fan.nrays()) ]) - n_rels
2208
self._chern_character = ch
2209
2210
if deg==None:
2211
return ch
2212
else:
2213
return ch.part_of_degree(deg)
2214
2215
def Todd_class(self, deg=None):
2216
"""
2217
Return the Todd class (of the tangent bundle) of the toric variety.
2218
2219
INPUT:
2220
2221
- ``deg`` -- integer (optional). The desired degree part.
2222
2223
OUTPUT:
2224
2225
- If the degree is specified, the degree-``deg`` part of the
2226
Todd class.
2227
2228
- If no degree is specified, the total Todd class.
2229
2230
REFERENCES:
2231
2232
..
2233
2234
http://en.wikipedia.org/wiki/Todd_class
2235
2236
EXAMPLES::
2237
2238
sage: dP6 = toric_varieties.dP6()
2239
sage: dP6.Todd_class()
2240
[-w^2 + 1/2*y + v + z + 1/2*w + 1]
2241
sage: dP6.Td()
2242
[-w^2 + 1/2*y + v + z + 1/2*w + 1]
2243
sage: dP6.integrate( dP6.Td() )
2244
1
2245
"""
2246
try:
2247
Td = self._Todd
2248
except AttributeError:
2249
Td = QQ(1)
2250
if self.dimension() >= 1:
2251
c1 = self.Chern_class(1)
2252
Td += QQ(1)/2 * c1
2253
if self.dimension() >= 2:
2254
c2 = self.Chern_class(2)
2255
Td += QQ(1)/12 * (c1**2 + c2)
2256
if self.dimension() >= 3:
2257
Td += QQ(1)/24 * c1*c2
2258
if self.dimension() >= 4:
2259
c3 = self.Chern_class(3)
2260
c4 = self.Chern_class(4)
2261
Td += -QQ(1)/720 * (c1**4 -4*c1**2*c2 -3*c2**2 -c1*c3 +c4)
2262
if self.dimension() >= 5:
2263
raise NotImplemented, 'Todd class is currently only implemented up to degree 4'
2264
self._Todd = Td
2265
2266
if deg==None:
2267
return Td
2268
else:
2269
return Td.part_of_degree(deg)
2270
2271
c = Chern_class
2272
ch = Chern_character
2273
Td = Todd_class
2274
2275
def Euler_number(self):
2276
"""
2277
Return the topological Euler number of the toric variety.
2278
2279
Sometimes, this is also called the Euler
2280
characteristic. :meth:`chi` is a synonym for
2281
:meth:`Euler_number`.
2282
2283
REFERENCES:
2284
2285
..
2286
2287
http://en.wikipedia.org/wiki/Euler_characteristic
2288
2289
EXAMPLES::
2290
2291
sage: P1xP1 = toric_varieties.P1xP1()
2292
sage: P1xP1.Euler_number()
2293
4
2294
sage: P1xP1.chi()
2295
4
2296
"""
2297
if "_chi" not in self.__dict__:
2298
if self.is_complete():
2299
chi = self.integrate(self.Chern_class())
2300
else:
2301
chi=0
2302
H = self.cohomology_basis()
2303
for d in range(0, self.dimension()+1):
2304
chi += (-1)**d * len(H[d])
2305
self._chi = chi
2306
return self._chi
2307
2308
chi = Euler_number
2309
2310
def K(self):
2311
r"""
2312
Returns the canonical divisor of the toric variety.
2313
2314
EXAMPLES:
2315
2316
Lets test that the del Pezzo surface `dP_6` has degree 6, as its name implies::
2317
2318
sage: dP6 = toric_varieties.dP6()
2319
sage: HH = dP6.cohomology_ring()
2320
sage: dP6.K()
2321
-V(x) - V(u) - V(y) - V(v) - V(z) - V(w)
2322
sage: dP6.integrate( HH(dP6.K())^2 )
2323
6
2324
"""
2325
from sage.schemes.toric.divisor import ToricDivisor
2326
return ToricDivisor(self, [-1]*self._fan.nrays())
2327
2328
def divisor(self, arg, base_ring=None, check=True, reduce=True):
2329
r"""
2330
Return a divisor.
2331
2332
INPUT:
2333
2334
The arguments are the same as in
2335
:func:`sage.schemes.toric.divisor.ToricDivisor`, with the
2336
exception of defining a divisor with a single integer: this method
2337
considers it to be the index of a ray of the :meth:`fan` of ``self``.
2338
2339
OUTPUT:
2340
2341
- A :class:`sage.schemes.toric.divisor.ToricDivisor_generic`
2342
2343
EXAMPLES::
2344
2345
sage: dP6 = toric_varieties.dP6()
2346
sage: dP6.coordinate_ring()
2347
Multivariate Polynomial Ring in x, u, y, v, z, w
2348
over Rational Field
2349
sage: dP6.divisor(range(6))
2350
V(u) + 2*V(y) + 3*V(v) + 4*V(z) + 5*V(w)
2351
sage: dP6.inject_variables()
2352
Defining x, u, y, v, z, w
2353
sage: dP6.divisor(x*u^3)
2354
V(x) + 3*V(u)
2355
2356
You can also construct divisors based on ray indices::
2357
2358
sage: dP6.divisor(0)
2359
V(x)
2360
sage: for i in range(0,dP6.fan().nrays()):
2361
... print dP6.divisor(i),
2362
... print ': generated by ray',
2363
... dP6.fan().ray(i)
2364
V(x) : generated by ray N(0, 1)
2365
V(u) : generated by ray N(-1, 0)
2366
V(y) : generated by ray N(-1, -1)
2367
V(v) : generated by ray N(0, -1)
2368
V(z) : generated by ray N(1, 0)
2369
V(w) : generated by ray N(1, 1)
2370
2371
TESTS:
2372
2373
We check that the issue :trac:`12812` is resolved::
2374
2375
sage: sum(dP6.divisor(i) for i in range(3))
2376
V(x) + V(u) + V(y)
2377
"""
2378
# Divisor by a ray index - must be treated here, see Trac #12812.
2379
if arg in ZZ:
2380
arg = [(1, self.gen(arg))]
2381
check = True # 1 must be coerced into the coefficient ring
2382
reduce = False
2383
from sage.schemes.toric.divisor import ToricDivisor
2384
return ToricDivisor(self, ring=base_ring, arg=arg,
2385
check=check, reduce=reduce)
2386
2387
def divisor_group(self, base_ring=ZZ):
2388
r"""
2389
Return the group of Weil divisors.
2390
2391
INPUT:
2392
2393
- ``base_ring`` -- the coefficient ring, usually ``ZZ``
2394
(default) or ``QQ``.
2395
2396
OUTPUT:
2397
2398
The (free abelian) group of Cartier divisors, that is, formal
2399
linear combinations of polynomial equations over the
2400
coefficient ring ``base_ring``.
2401
2402
These need not be toric (=defined by monomials), but allow
2403
general polynomials. The output will be an instance of
2404
:class:`sage.schemes.generic.divisor_group.DivisorGroup_generic`.
2405
2406
.. WARNING::
2407
2408
You almost certainly want the group of toric divisors, see
2409
:meth:`toric_divisor_group`. The toric divisor group is
2410
generated by the rays of the fan. The general divisor
2411
group has no toric functionality implemented.
2412
2413
EXAMPLES::
2414
2415
sage: dP6 = toric_varieties.dP6()
2416
sage: Div = dP6.divisor_group(); Div
2417
Group of ZZ-Divisors on 2-d CPR-Fano toric variety
2418
covered by 6 affine patches
2419
sage: Div(x)
2420
V(x)
2421
"""
2422
from sage.schemes.generic.divisor_group import DivisorGroup
2423
return DivisorGroup(self, base_ring)
2424
2425
def toric_divisor_group(self, base_ring=ZZ):
2426
r"""
2427
Return the group of toric (T-Weil) divisors.
2428
2429
INPUT:
2430
2431
- ``base_ring`` -- the coefficient ring, usually ``ZZ``
2432
(default) or ``QQ``.
2433
2434
OUTPUT:
2435
2436
The free Abelian agroup of toric Weil divisors, that is,
2437
formal ``base_ring``-linear combinations of codimension-one
2438
toric subvarieties. The output will be an instance of
2439
:class:`sage.schemes.toric.divisor.ToricDivisorGroup`.
2440
2441
The `i`-th generator of the divisor group is the divisor where
2442
the `i`-th homogeneous coordinate vanishes, `\{z_i=0\}`.
2443
2444
EXAMPLES::
2445
2446
sage: dP6 = toric_varieties.dP6()
2447
sage: TDiv = dP6.toric_divisor_group(); TDiv
2448
Group of toric ZZ-Weil divisors on 2-d CPR-Fano toric variety
2449
covered by 6 affine patches
2450
sage: TDiv == dP6.toric_divisor_group()
2451
True
2452
sage: TDiv.gens()
2453
(V(x), V(u), V(y), V(v), V(z), V(w))
2454
sage: dP6.coordinate_ring()
2455
Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field
2456
"""
2457
from sage.schemes.toric.divisor import ToricDivisorGroup
2458
return ToricDivisorGroup(self, base_ring);
2459
2460
def _semigroup_ring(self, cone=None, names=None):
2461
r"""
2462
Return a presentation of the semigroup ring for the dual of ``cone``.
2463
2464
INPUT:
2465
2466
See :meth:`Spec`.
2467
2468
OUTPUT:
2469
2470
For the given ``cone`` `\sigma`, return a tuple consisting of
2471
2472
* a polynomial ring `R`,
2473
2474
* an ideal `I\in R`,
2475
2476
* the dual cone `\sigma^\vee`
2477
2478
such that `R/I \sim k[\sigma^\vee \cap M]`, where `k` is the
2479
:meth:`base_ring` of the toric variety.
2480
2481
EXAMPLES::
2482
2483
sage: A2Z2 = Cone([(0,1),(2,1)])
2484
sage: AffineToricVariety(A2Z2)._semigroup_ring()
2485
(Multivariate Polynomial Ring in z0, z1, z2 over Rational Field,
2486
Ideal (-z0*z1 + z2^2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field,
2487
2-d cone in 2-d lattice M)
2488
2489
sage: P2 = toric_varieties.P2()
2490
sage: cone = P2.fan().generating_cone(0)
2491
sage: P2._semigroup_ring(cone)
2492
(Multivariate Polynomial Ring in z0, z1 over Rational Field,
2493
Ideal (0) of Multivariate Polynomial Ring in z0, z1 over Rational Field,
2494
2-d cone in 2-d lattice M)
2495
sage: P2.change_ring(GF(101))._semigroup_ring(cone)
2496
(Multivariate Polynomial Ring in z0, z1 over Finite Field of size 101,
2497
Ideal (0) of Multivariate Polynomial Ring in z0, z1 over Finite Field of size 101,
2498
2-d cone in 2-d lattice M)
2499
"""
2500
from sage.schemes.toric.ideal import ToricIdeal
2501
if cone is None:
2502
assert self.is_affine(), \
2503
'You may only omit the cone argument for an affine toric variety!'
2504
cone = self.fan().generating_cone(0)
2505
2506
cone = self.fan().embed(cone)
2507
dual = cone.dual()
2508
basis = dual.Hilbert_basis()
2509
N = len(basis)
2510
names = normalize_names(names, N, DEFAULT_PREFIX)
2511
A = matrix(ZZ,basis).transpose()
2512
IA = ToricIdeal(A, names, base_ring=self.base_ring())
2513
return (IA.ring(), IA, dual)
2514
2515
def Spec(self, cone=None, names=None):
2516
r"""
2517
Return the spectrum associated to the dual cone.
2518
2519
Let `\sigma \in N_\RR` be a cone and `\sigma^\vee \cap M` the
2520
associated semigroup of lattice points in the dual cone. Then
2521
2522
.. MATH::
2523
2524
S = \CC[\sigma^\vee \cap M]
2525
2526
is a `\CC`-algebra. It is spanned over `\CC` by the points of
2527
`\sigma \cap N`, addition is formal linear combination of
2528
lattice points, and multiplication of lattice points is the
2529
semigroup law (that is, addition of lattice points). The
2530
`\CC`-algebra `S` then defines a scheme `\mathop{Spec}(S)`.
2531
2532
For example, if `\sigma=\{(x,y)|x\geq 0,y\geq 0\}` is the
2533
first quadrant then `S` is the polynomial ring in two
2534
variables. The associated scheme is `\mathop{Spec}(S) =
2535
\CC^2`.
2536
2537
The same construction works over any base field, this
2538
introduction only used `\CC` for simplicity.
2539
2540
INPUT:
2541
2542
- ``cone`` -- a :class:`Cone
2543
<sage.geometry.cone.ConvexRationalPolyhedralCone>`. Can be
2544
omitted for an affine toric variety, in which case the
2545
(unique) generating cone is used.
2546
2547
- ``names`` -- (optional). Names of variables for the
2548
semigroup ring, see :func:`normalize_names` for acceptable
2549
formats. If not given, indexed variable names will be
2550
created automatically.
2551
2552
Output:
2553
2554
The spectrum of the semigroup ring `\CC[\sigma^\vee \cap M]`.
2555
2556
EXAMPLES::
2557
2558
sage: quadrant = Cone([(1,0),(0,1)])
2559
sage: AffineToricVariety(quadrant).Spec()
2560
Spectrum of Quotient of Multivariate Polynomial Ring
2561
in z0, z1 over Rational Field by the ideal (0)
2562
2563
A more interesting example::
2564
2565
sage: A2Z2 = Cone([(0,1),(2,1)])
2566
sage: AffineToricVariety(A2Z2).Spec(names='u,v,t')
2567
Spectrum of Quotient of Multivariate Polynomial Ring
2568
in u, v, t over Rational Field by the ideal (-u*v + t^2)
2569
"""
2570
from sage.schemes.generic.spec import Spec
2571
R, I, dualcone = self._semigroup_ring(cone, names)
2572
return Spec(R.quotient(I))
2573
2574
def affine_algebraic_patch(self, cone=None, names=None):
2575
r"""
2576
Return the patch corresponding to ``cone`` as an affine
2577
algebraic subvariety.
2578
2579
INPUT:
2580
2581
- ``cone`` -- a :class:`Cone
2582
<sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma`
2583
of the fan. It can be omitted for an affine toric variety,
2584
in which case the single generating cone is used.
2585
2586
OUTPUT:
2587
2588
A :class:`affine algebraic subscheme
2589
<sage.schemes.generic.algebraic_scheme.AlgebraicScheme_subscheme_affine>`
2590
corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)`
2591
associated to the cone `\sigma`.
2592
2593
See also :meth:`affine_patch`, which expresses the patches as
2594
subvarieties of affine toric varieties instead.
2595
2596
EXAMPLES::
2597
2598
sage: cone = Cone([(0,1),(2,1)])
2599
sage: A2Z2 = AffineToricVariety(cone)
2600
sage: A2Z2.affine_algebraic_patch()
2601
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2602
-z0*z1 + z2^2
2603
sage: A2Z2.affine_algebraic_patch(Cone([(0,1)]), names='x, y, t')
2604
Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
2605
1
2606
"""
2607
R, I, dualcone = self._semigroup_ring(cone, names)
2608
patch_cover = AffineSpace(R)
2609
patch = patch_cover.subscheme(I)
2610
return patch
2611
2612
2613
def _orbit_closure_projection(self, cone, x):
2614
r"""
2615
Return the projection of ``x`` onto the quotient lattice of ``cone``.
2616
2617
INPUT:
2618
2619
- ``cone`` -- a :class:`cone
2620
<sage.geometry.cone.ConvexRationalPolyhedralCone>` of the :meth:`fan`
2621
of ``self``;
2622
2623
- ``x`` -- a lattice point or a cone of the :meth:`fan` of ``self``.
2624
2625
OUTPUT:
2626
2627
- the projection of ``x`` onto the quotient lattice of ``cone``, which
2628
is either a lattice point or a cone depending on the type of ``x``.
2629
This quotient lattice is the ambient lattice for the fan of the orbit
2630
closure corresponding to ``cone``.
2631
2632
If ``x`` is a cone not in the star of ``cone``, an ``IndexError`` is
2633
raised.
2634
2635
See :meth:`orbit_closure` for more details.
2636
2637
.. warning::
2638
2639
Due to incomplete support of quotient lattices (as of 12-07-2011),
2640
this function actually operates with a generic toric lattice of the
2641
same dimension as the qppropriate quotient lattice. This behaviour
2642
is likely to change in the future releases of Sage.
2643
2644
EXAMPLES::
2645
2646
sage: P2 = toric_varieties.P2()
2647
sage: H = P2.fan(1)[0]
2648
sage: [P2._orbit_closure_projection(H, p) for p in P2.fan().rays()]
2649
[(0), (1), (-1)]
2650
sage: P2._orbit_closure_projection(H, P2.fan(2)[0])
2651
1-d cone in 1-d lattice N
2652
"""
2653
cone = self.fan().embed(cone)
2654
quot = cone.sublattice_quotient()
2655
if x in cone.lattice():
2656
return vector(quot(x))
2657
2658
assert is_Cone(x)
2659
rays = [ vector(quot(r)) for r in x.rays() ]
2660
return Cone(rays)
2661
2662
# TODO: make the following work nicely.
2663
#if x in cone.lattice():
2664
#return quot(x)
2665
#assert is_Cone(x)
2666
#return Cone(x.rays(), lattice=quot)
2667
2668
2669
def orbit_closure(self, cone):
2670
r"""
2671
Return the orbit closure of ``cone``.
2672
2673
The cones `\sigma` of a fan `\Sigma` are in one-to-one correspondence
2674
with the torus orbits `O(\sigma)` of the corresponding toric variety
2675
`X_\Sigma`. Each orbit is isomorphic to a lower dimensional torus (of
2676
dimension equal to the codimension of `\sigma`). Just like the toric
2677
variety `X_\Sigma` itself, these orbits are (partially) compactified by
2678
lower-dimensional orbits. In particular, one can define the closure
2679
`V(\sigma)` of the torus orbit `O(\sigma)` in the ambient toric
2680
variety `X_\Sigma`, which is again a toric variety.
2681
2682
See Proposition 3.2.7 of [CLS]_ for more details.
2683
2684
INPUT:
2685
2686
- ``cone`` -- a :class:`cone
2687
<sage.geometry.cone.ConvexRationalPolyhedralCone>` of the fan.
2688
2689
OUTPUT:
2690
2691
- a torus orbit closure associated to ``cone`` as a
2692
:class:`toric variety <ToricVariety_field>`.
2693
2694
EXAMPLES::
2695
2696
sage: P1xP1 = toric_varieties.P1xP1()
2697
sage: H = P1xP1.fan(1)[0]
2698
sage: P1xP1.orbit_closure(H)
2699
1-d toric variety covered by 2 affine patches
2700
"""
2701
cone = self.fan().embed(cone)
2702
cones = []
2703
for star_cone in cone.star_generators():
2704
cones.append( self._orbit_closure_projection(cone, star_cone) )
2705
from sage.geometry.fan import discard_faces
2706
return ToricVariety(Fan(discard_faces(cones), check=False))
2707
2708
2709
2710
2711
def normalize_names(names=None, ngens=None, prefix=None, indices=None,
2712
return_prefix=False):
2713
r"""
2714
Return a list of names in the standard form.
2715
2716
INPUT:
2717
2718
All input parameters are optional.
2719
2720
- ``names`` -- names given either as a single string (with individual
2721
names separated by commas or spaces) or a list of strings with each
2722
string specifying a name. If the last name ends with the plus sign,
2723
"+", this name will be used as ``prefix`` (even if ``prefix`` was
2724
given explicitly);
2725
2726
- ``ngens`` -- number of names to be returned;
2727
2728
- ``prefix`` -- prefix for the indexed names given as a string;
2729
2730
- ``indices`` -- list of integers (default: ``range(ngens)``) used as
2731
indices for names with ``prefix``. If given, must be of length
2732
``ngens``;
2733
2734
- ``return_prefix`` -- if ``True``, the last element of the returned list
2735
will contain the prefix determined from ``names`` or given as the
2736
parameter ``prefix``. This is useful if you may need more names in the
2737
future.
2738
2739
OUTPUT:
2740
2741
- list of names given as strings.
2742
2743
These names are constructed in the following way:
2744
2745
#. If necessary, split ``names`` into separate names.
2746
#. If the last name ends with "+", put it into ``prefix``.
2747
#. If ``ngens`` was given, add to the names obtained so far as many
2748
indexed names as necessary to get this number. If the ``k``-th name of
2749
the *total* list of names is indexed, it is
2750
``prefix + str(indices[k])``. If there were already more names than
2751
``ngens``, discard "extra" ones.
2752
#. Check if constructed names are valid. See :func:`certify_names` for
2753
details.
2754
#. If the option ``return_prefix=True`` was given, add ``prefix`` to the
2755
end of the list.
2756
2757
EXAMPLES:
2758
2759
As promised, all parameters are optional::
2760
2761
sage: from sage.schemes.toric.variety import normalize_names
2762
sage: normalize_names()
2763
[]
2764
2765
One of the most common uses is probably this one::
2766
2767
sage: normalize_names("x+", 4)
2768
['x0', 'x1', 'x2', 'x3']
2769
2770
Now suppose that you want to enumerate your variables starting with one
2771
instead of zero::
2772
2773
sage: normalize_names("x+", 4, indices=range(1,5))
2774
['x1', 'x2', 'x3', 'x4']
2775
2776
You may actually have an arbitrary enumeration scheme::
2777
2778
sage: normalize_names("x+", 4, indices=[1, 10, 100, 1000])
2779
['x1', 'x10', 'x100', 'x1000']
2780
2781
Now let's add some "explicit" names::
2782
2783
sage: normalize_names("x y z t+", 4)
2784
['x', 'y', 'z', 't3']
2785
2786
Note that the "automatic" name is ``t3`` instead of ``t0``. This may seem
2787
weird, but the reason for this behaviour is that the fourth name in this
2788
list will be the same no matter how many explicit names were given::
2789
2790
sage: normalize_names("x y t+", 4)
2791
['x', 'y', 't2', 't3']
2792
2793
This is especially useful if you get ``names`` from a user but want to
2794
specify all default names::
2795
2796
sage: normalize_names("x, y", 4, prefix="t")
2797
['x', 'y', 't2', 't3']
2798
2799
In this format, the user can easily override your choice for automatic
2800
names::
2801
2802
sage: normalize_names("x y s+", 4, prefix="t")
2803
['x', 'y', 's2', 's3']
2804
2805
Let's now use all parameters at once::
2806
2807
sage: normalize_names("x, y, s+", 4, prefix="t",
2808
... indices=range(1,5), return_prefix=True)
2809
['x', 'y', 's3', 's4', 's']
2810
2811
Note that you still need to give indices for all names, even if some of
2812
the first ones will be "wasted" because of the explicit names. The reason
2813
is the same as before - this ensures consistency of automatically
2814
generated names, no matter how many explicit names were given.
2815
2816
The prefix is discarded if ``ngens`` was not given::
2817
2818
sage: normalize_names("alpha, beta, gamma, zeta+")
2819
['alpha', 'beta', 'gamma']
2820
2821
Finally, let's take a look at some possible mistakes::
2822
2823
sage: normalize_names("123")
2824
Traceback (most recent call last):
2825
...
2826
ValueError: name must start with a letter! Got 123
2827
2828
A more subtle one::
2829
2830
sage: normalize_names("x1", 4, prefix="x")
2831
Traceback (most recent call last):
2832
...
2833
ValueError: names must be distinct! Got: ['x1', 'x1', 'x2', 'x3']
2834
"""
2835
if names is None:
2836
names = []
2837
elif isinstance(names, str):
2838
names = names.replace(",", " ").split()
2839
else:
2840
try:
2841
names = list(names)
2842
except TypeError:
2843
raise TypeError(
2844
"names must be a string or a list or tuple of them!")
2845
for name in names:
2846
if not isinstance(name, str):
2847
raise TypeError(
2848
"names must be a string or a list or tuple of them!")
2849
if names and names[-1].endswith("+"):
2850
prefix = names.pop()[:-1]
2851
if ngens is None:
2852
ngens = len(names)
2853
if len(names) < ngens:
2854
if prefix is None:
2855
raise IndexError("need %d names but only %d are given!"
2856
% (ngens, len(names)))
2857
if indices is None:
2858
indices = range(ngens)
2859
elif len(indices) != ngens:
2860
raise ValueError("need exactly %d indices, but got %d!"
2861
% (ngens, len(indices)))
2862
names += [prefix + str(i) for i in indices[len(names):]]
2863
if len(names) > ngens:
2864
names = names[:ngens]
2865
# Check that all given and constructed names are valid
2866
certify_names(names)
2867
if return_prefix:
2868
names.append(prefix)
2869
return names
2870
2871
2872
def certify_names(names):
2873
r"""
2874
Make sure that ``names`` are valid in Python.
2875
2876
INPUT:
2877
2878
- ``names`` -- list of strings.
2879
2880
OUTPUT:
2881
2882
- none, but a ``ValueError`` exception is raised if ``names`` are invalid.
2883
2884
Each name must satisfy the following requirements:
2885
2886
* Be non-empty.
2887
* Contain only (Latin) letters, digits, and underscores ("_").
2888
* Start with a letter.
2889
2890
In addition, all names must be distinct.
2891
2892
EXAMPLES::
2893
2894
sage: from sage.schemes.toric.variety import certify_names
2895
sage: certify_names([])
2896
sage: certify_names(["a", "x0", "x_45"])
2897
sage: certify_names(["", "x0", "x_45"])
2898
Traceback (most recent call last):
2899
...
2900
ValueError: name must be nonempty!
2901
sage: certify_names(["a", "0", "x_45"])
2902
Traceback (most recent call last):
2903
...
2904
ValueError: name must start with a letter! Got 0
2905
sage: certify_names(["a", "x0", "@_45"])
2906
Traceback (most recent call last):
2907
...
2908
ValueError: name must be alphanumeric! Got @_45
2909
sage: certify_names(["a", "x0", "x0"])
2910
Traceback (most recent call last):
2911
...
2912
ValueError: names must be distinct! Got: ['a', 'x0', 'x0']
2913
"""
2914
for name in names:
2915
if not name:
2916
raise ValueError("name must be nonempty!")
2917
if not name.isalnum() and not name.replace("_","").isalnum():
2918
# Must be alphanumeric except for non-leading '_'
2919
raise ValueError("name must be alphanumeric! Got %s" % name)
2920
if not name[0].isalpha():
2921
raise ValueError("name must start with a letter! Got %s" % name)
2922
if len(set(names)) != len(names):
2923
raise ValueError("names must be distinct! Got: %s" % names)
2924
2925
2926
#*****************************************************************
2927
class CohomologyRing(QuotientRing_generic, UniqueRepresentation):
2928
r"""
2929
The (even) cohomology ring of a toric variety.
2930
2931
Irregardles of the variety's base ring, we always work with the
2932
variety over `\CC` and its topology.
2933
2934
The cohomology is always the singular cohomology with
2935
`\QQ`-coefficients. Note, however, that the cohomology of smooth
2936
toric varieties is torsion-free, so there is no loss of
2937
information in that case.
2938
2939
Currently, the toric variety must not be "too singular". See
2940
:meth:`ToricVariety_field.cohomology_ring` for a detailed
2941
description of which toric varieties are admissible. For such
2942
varieties the odd-dimensional cohomology groups vanish.
2943
2944
.. WARNING::
2945
2946
You should not create instances of this class manually. Use
2947
:meth:`ToricVariety_field.cohomology_ring` to generate the
2948
cohomology ring.
2949
2950
INPUT:
2951
2952
- ``variety`` -- a toric variety. Currently, the toric variety
2953
must be at least an orbifold. See
2954
:meth:`ToricVariety_field.cohomology_ring` for a detailed
2955
description of which toric varieties are admissible.
2956
2957
EXAMPLES::
2958
2959
sage: P2 = toric_varieties.P2()
2960
sage: P2.cohomology_ring()
2961
Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 3 affine patches
2962
2963
This is equivalent to::
2964
2965
sage: from sage.schemes.toric.variety import CohomologyRing
2966
sage: CohomologyRing(P2)
2967
Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 3 affine patches
2968
"""
2969
2970
def __init__(self, variety):
2971
r"""
2972
See :class:`CohomologyRing` for documentation.
2973
2974
TESTS::
2975
2976
sage: P2 = toric_varieties.P2()
2977
sage: P2.cohomology_ring()
2978
Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 3 affine patches
2979
2980
TESTS::
2981
2982
sage: cone1 = Cone([(1,0)]); cone2 = Cone([(1,0)])
2983
sage: cone1 is cone2
2984
False
2985
sage: fan1 = Fan([cone1]); fan2 = Fan([cone2])
2986
sage: fan1 is fan2
2987
False
2988
sage: X1 = ToricVariety(fan1); X2 = ToricVariety(fan2)
2989
sage: X1 is X2
2990
False
2991
sage: X1.cohomology_ring() is X2.cohomology_ring() # see http://trac.sagemath.org/sage_trac/ticket/10325
2992
True
2993
sage: TDiv = X1.toric_divisor_group()
2994
sage: X1.toric_divisor_group() is TDiv
2995
True
2996
sage: X2.toric_divisor_group() is TDiv
2997
True
2998
sage: TDiv.scheme() is X1 # as you expect
2999
True
3000
sage: TDiv.scheme() is X2 # perhaps less obvious, but toric_divisor_group is unique!
3001
False
3002
sage: TDiv.scheme() == X2 # isomorphic, but not necessarily identical
3003
True
3004
sage: TDiv.scheme().cohomology_ring() is X2.cohomology_ring() # this is where it gets tricky
3005
True
3006
sage: TDiv.gen(0).Chern_character() * X2.cohomology_ring().one()
3007
[1]
3008
"""
3009
self._variety = variety
3010
3011
if not variety.is_orbifold():
3012
raise NotImplementedError, 'Requires an orbifold toric variety.'
3013
3014
R = PolynomialRing(QQ, variety.variable_names())
3015
self._polynomial_ring = R
3016
3017
I = variety._fan.linear_equivalence_ideal(R) + variety._fan.Stanley_Reisner_ideal(R)
3018
super(CohomologyRing, self).__init__(R, I, names=variety.variable_names())
3019
3020
def _repr_(self):
3021
r"""
3022
Return a string representation of the cohomology ring.
3023
3024
OUTPUT:
3025
3026
A string.
3027
3028
EXAMPLES::
3029
3030
sage: toric_varieties.P2().cohomology_ring()._repr_()
3031
'Rational cohomology ring of a 2-d CPR-Fano toric variety covered by 3 affine patches'
3032
"""
3033
return 'Rational cohomology ring of a '+self._variety._repr_()
3034
3035
def _latex_(self):
3036
r"""
3037
Return a latex representation of the cohomology ring.
3038
3039
OUTPUT:
3040
3041
A string.
3042
3043
EXAMPLES::
3044
3045
sage: cohomology_ring = toric_varieties.P2().cohomology_ring()
3046
sage: cohomology_ring._latex_()
3047
'H^\\ast\\left(\\mathbb{P}_{\\Delta^{2}},\\QQ\\right)'
3048
"""
3049
return 'H^\\ast\\left('+self._variety._latex_()+',\QQ\\right)'
3050
3051
def _element_constructor_(self,x):
3052
r"""
3053
Construct a :class:`CohomologyClass`.
3054
3055
INPUT::
3056
3057
- ``x`` -- something that defines a cohomology class. Either a
3058
cohomology class, a cone of the fan, or something that can
3059
be converted into a polynomial in the homogeneous
3060
coordinates.
3061
3062
OUTPUT:
3063
3064
The :class:`CohomologyClass` defined by ``x``.
3065
3066
EXAMPLES::
3067
3068
sage: dP6 = toric_varieties.dP6()
3069
sage: H = dP6.cohomology_ring()
3070
sage: cone = dP6.fan().cone_containing(2,3); cone
3071
2-d cone of Rational polyhedral fan in 2-d lattice N
3072
sage: H(cone) # indirect doctest
3073
[-w^2]
3074
sage: H( Cone(cone) )
3075
[-w^2]
3076
sage: H( dP6.fan(0)[0] ) # trivial cone
3077
[1]
3078
3079
Non-smooth cones are a bit tricky. For such a cone, the
3080
intersection of the divisors corresponding to the rays is
3081
still proportional to the product of the variables, but the
3082
coefficient is a multiple depending on the orbifold
3083
singularity. See also [CLS]_, Lemma 12.5.2::
3084
3085
sage: P2_123 = toric_varieties.P2_123()
3086
sage: HH = P2_123.cohomology_ring()
3087
sage: HH(Cone([(1,0)])) * HH(Cone([(-2,-3)]))
3088
[2*z2^2]
3089
sage: HH(Cone([(1,0), (-2,-3)]))
3090
[6*z2^2]
3091
sage: [ HH(c) for c in P2_123.fan().generating_cones() ]
3092
[[6*z2^2], [6*z2^2], [6*z2^2]]
3093
sage: P2_123.volume_class()
3094
[6*z2^2]
3095
sage: [ HH(c.facets()[0]) * HH(c.facets()[1]) for c in P2_123.fan().generating_cones() ]
3096
[[6*z2^2], [3*z2^2], [2*z2^2]]
3097
3098
Numbers will be converted into the ring::
3099
3100
sage: P2 = toric_varieties.P2()
3101
sage: H = P2.cohomology_ring()
3102
sage: H._element_constructor_(1)
3103
[1]
3104
sage: H(1)
3105
[1]
3106
sage: type( H(1) )
3107
<class 'sage.schemes.toric.variety.CohomologyClass'>
3108
sage: P2.inject_variables()
3109
Defining x, y, z
3110
sage: H(1+x*y+z)
3111
[z^2 + z + 1]
3112
"""
3113
fan = self._variety.fan()
3114
if isinstance(x, CohomologyClass) and x.parent()==self:
3115
return x
3116
if isinstance(x, QuotientRingElement):
3117
x = x.lift()
3118
elif is_Cone(x):
3119
cone = fan.embed(x)
3120
assert cone.ambient() is fan
3121
mult = cone.ray_matrix().index_in_saturation()
3122
x = prod((self.cover_ring().gen(i) for i in cone.ambient_ray_indices()),
3123
z=self.cover_ring().one()) * mult
3124
else:
3125
try:
3126
# divisor, for example, know how to compute their own cohomology class
3127
return x.cohomology_class()
3128
except AttributeError:
3129
# this ensures that rationals are converted to cohomology ring elements
3130
x = self.cover_ring()(x)
3131
return CohomologyClass(self, x)
3132
3133
# We definitely should not override __call__, but since our
3134
# superclass QuotientRing_generic does not adhere to the coercion
3135
# model we cannot either. See
3136
# http://trac.sagemath.org/sage_trac/ticket/9429
3137
def __call__(self, x, coerce=True):
3138
r"""
3139
Turn ``x`` into a ``CohomologyClass``.
3140
3141
EXAMPLES::
3142
3143
sage: P2 = toric_varieties.P2()
3144
sage: H = P2.cohomology_ring()
3145
sage: H(1)
3146
[1]
3147
sage: type( H(1) )
3148
<class 'sage.schemes.toric.variety.CohomologyClass'>
3149
"""
3150
return self._element_constructor_(x)
3151
3152
def gens(self):
3153
r"""
3154
Return the generators of the cohomology ring.
3155
3156
OUTPUT:
3157
3158
A tuple of generators, one for each toric divisor of the toric
3159
variety ``X``. The order is the same as the ordering of the
3160
rays of the fan ``X.fan().rays()``, which is also the same as
3161
the ordering of the one-cones in ``X.fan(1)``
3162
3163
EXAMPLES::
3164
3165
sage: P2 = toric_varieties.P2()
3166
sage: P2.cohomology_ring().gens()
3167
([z], [z], [z])
3168
"""
3169
if "_gens" not in self.__dict__:
3170
self._gens = tuple( self.gen(i) for i in range(0,self._variety.fan().nrays()) )
3171
return self._gens
3172
3173
def gen(self, i):
3174
r"""
3175
Return the generators of the cohomology ring.
3176
3177
INPUT:
3178
3179
- ``i`` -- integer.
3180
3181
OUTPUT:
3182
3183
The ``i``-th generator of the cohomology ring. If we denote
3184
the toric variety by ``X``, then this generator is
3185
associated to the ray ``X.fan().ray(i)``, which spans the
3186
one-cone ``X.fan(1)[i]``
3187
3188
EXAMPLES::
3189
3190
sage: P2 = toric_varieties.P2()
3191
sage: P2.cohomology_ring().gen(2)
3192
[z]
3193
"""
3194
return CohomologyClass(self, self._polynomial_ring.gen(i))
3195
3196
3197
#*****************************************************************
3198
def is_CohomologyClass(x):
3199
r"""
3200
Check whether ``x`` is a cohomology class of a toric variety.
3201
3202
INPUT:
3203
3204
- ``x`` -- anything.
3205
3206
OUTPUT:
3207
3208
``True`` or ``False`` depending on whether ``x`` is an instance of
3209
:class:`CohomologyClass`
3210
3211
EXAMPLES::
3212
3213
sage: P2 = toric_varieties.P2()
3214
sage: HH = P2.cohomology_ring()
3215
sage: from sage.schemes.toric.variety import is_CohomologyClass
3216
sage: is_CohomologyClass( HH.one() )
3217
True
3218
sage: is_CohomologyClass( HH(P2.fan(1)[0]) )
3219
True
3220
sage: is_CohomologyClass('z')
3221
False
3222
"""
3223
return isinstance(x,CohomologyClass)
3224
3225
3226
#*****************************************************************
3227
class CohomologyClass(QuotientRingElement):
3228
r"""
3229
An element of the :class:`CohomologyRing`.
3230
3231
.. WARNING::
3232
3233
You should not create instances of this class manually. The
3234
generators of the cohomology ring as well as the cohomology
3235
classes associated to cones of the fan can be obtained from
3236
:meth:`ToricVariety_field.cohomology_ring`.
3237
3238
EXAMPLES::
3239
3240
sage: P2 = toric_varieties.P2()
3241
sage: P2.cohomology_ring().gen(0)
3242
[z]
3243
sage: HH = P2.cohomology_ring()
3244
sage: HH.gen(0)
3245
[z]
3246
sage: cone = P2.fan(1)[0]; HH(cone)
3247
[z]
3248
"""
3249
3250
def __init__(self, cohomology_ring, representative):
3251
r"""
3252
Construct the cohomology class.
3253
3254
INPUT:
3255
3256
- ``cohomology_ring`` -- :class:`CohomologyRing`.
3257
3258
- ``representative`` -- a polynomial in the generators of the cohomology ring.
3259
3260
OUTPUT:
3261
3262
An instance of :class:`CohomologyClass`.
3263
3264
EXAMPLES::
3265
3266
sage: P2 = toric_varieties.P2()
3267
sage: H = P2.cohomology_ring()
3268
sage: from sage.schemes.toric.variety import CohomologyClass
3269
sage: CohomologyClass(H, H.defining_ideal().ring().zero() )
3270
[0]
3271
"""
3272
assert representative in cohomology_ring.defining_ideal().ring(), \
3273
'The given representative is not in the parent polynomial ring.'
3274
super(CohomologyClass, self).__init__(cohomology_ring, representative)
3275
3276
def _repr_(self):
3277
r"""
3278
Return a string representation of the cohomology class.
3279
3280
OUTPUT:
3281
3282
A string.
3283
3284
EXAMPLES::
3285
3286
sage: toric_varieties.P2().cohomology_ring().gen(0)._repr_()
3287
'[z]'
3288
"""
3289
return '['+super(CohomologyClass,self)._repr_()+']'
3290
3291
def _latex_(self):
3292
r"""
3293
Return a latex representation of the cohomology class.
3294
3295
OUTPUT:
3296
3297
A string.
3298
3299
EXAMPLES::
3300
3301
sage: cohomology_class = toric_varieties.P2().cohomology_ring().gen(0)^2/2
3302
sage: cohomology_class._latex_()
3303
'\\left[ \\frac{1}{2} z^{2} \\right]'
3304
"""
3305
return r'\left[ %s \right]' % latex(self.lift())
3306
3307
def deg(self):
3308
r"""
3309
The degree of the cohomology class.
3310
3311
OUTPUT:
3312
3313
An integer `d` such that the cohomology class is in degree
3314
`2d`. If the cohomology class is of mixed degree, the highest
3315
degree is returned.
3316
3317
EXAMPLES::
3318
3319
sage: P2 = toric_varieties.P2()
3320
sage: P2.cohomology_ring().gen(0).deg()
3321
1
3322
sage: P2.cohomology_ring().zero().deg()
3323
-1
3324
"""
3325
return self.lift().degree()
3326
3327
def part_of_degree(self, d):
3328
r"""
3329
Project the (mixed-degree) cohomology class to the given degree.
3330
3331
.. MATH::
3332
3333
\mathop{pr}\nolimits_d:~ H^\bullet(X_\Delta,\QQ) \to H^{2d}(X_\Delta,\QQ)
3334
3335
INPUT:
3336
3337
- An integer ``d``
3338
3339
OUTPUT:
3340
3341
- The degree-``2d`` part of the cohomology class.
3342
3343
EXAMPLES::
3344
3345
sage: P1xP1 = toric_varieties.P1xP1()
3346
sage: t = P1xP1.cohomology_ring().gen(0)
3347
sage: y = P1xP1.cohomology_ring().gen(2)
3348
sage: 3*t+4*t^2*y+y+t*y+t+1
3349
[t*y + 4*t + y + 1]
3350
sage: (3*t+4*t^2*y+y+t*y+t+1).part_of_degree(1)
3351
[4*t + y]
3352
"""
3353
Q = self.parent()
3354
# We iterate over monomials of self.lift()
3355
p = filter( lambda x: x[1].total_degree() == d, self.lift() )
3356
if len(p)==0:
3357
return Q.zero()
3358
else:
3359
return Q(sum(x[0]*x[1] for x in p))
3360
3361
def exp(self):
3362
"""
3363
Exponentiate ``self``.
3364
3365
.. NOTE::
3366
3367
The exponential `\exp(x)` of a rational number `x` is
3368
usually not rational. Therefore, the cohomology class must
3369
not have a constant (degree zero) part. The coefficients
3370
in the Taylor series of `\exp` are rational, so any
3371
cohomology class without constant term can be
3372
exponentiated.
3373
3374
OUTPUT
3375
3376
The cohomology class `\exp(` ``self`` `)` if the constant part
3377
vanishes, otherwise a ``ValueError`` is raised.
3378
3379
EXAMPLES::
3380
3381
sage: P2 = toric_varieties.P2()
3382
sage: H_class = P2.cohomology_ring().gen(0)
3383
sage: H_class
3384
[z]
3385
sage: H_class.exp()
3386
[1/2*z^2 + z + 1]
3387
"""
3388
if not self.part_of_degree(0).is_zero():
3389
raise ValueError, 'Must not have a constant part.'
3390
exp_x = self.parent().one()
3391
for d in range(1,self.parent()._variety.dimension()+1):
3392
exp_x += self**d / factorial(d)
3393
return exp_x
3394
3395
3396