Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/toric/fano_variety.py
4126 views
1
r"""
2
Fano toric varieties
3
4
This module provides support for (Crepant Partial Resolutions of) Fano toric
5
varieties, corresponding to crepant subdivisions of face fans of reflexive
6
:class:`lattice polytopes
7
<sage.geometry.lattice_polytope.LatticePolytopeClass>`.
8
The interface is provided via :func:`CPRFanoToricVariety`.
9
10
A careful exposition of different flavours of Fano varieties can be found in
11
the paper by Benjamin Nill [Nill2005]_. The main goal of this module is to
12
support work with **Gorenstein weak Fano toric varieties**. Such a variety
13
corresponds to a **coherent crepant refinement of the normal fan of a
14
reflexive polytope** `\Delta`, where crepant means that primitive generators
15
of the refining rays lie on the facets of the polar polytope `\Delta^\circ`
16
and coherent (a.k.a. regular or projective) means that there exists a strictly
17
upper convex piecewise linear function whose domains of linearity are
18
precisely the maximal cones of the subdivision. These varieties are important
19
for string theory in physics, as they serve as ambient spaces for mirror pairs
20
of Calabi-Yau manifolds via constructions due to Victor V. Batyrev
21
[Batyrev1994]_ and Lev A. Borisov [Borisov1993]_.
22
23
From the combinatorial point of view "crepant" requirement is much more simple
24
and natural to work with than "coherent." For this reason, the code in this
25
module will allow work with arbitrary crepant subdivisions without checking
26
whether they are coherent or not. We refer to corresponding toric varieties as
27
**CPR-Fano toric varieties**.
28
29
REFERENCES:
30
31
.. [Batyrev1994]
32
Victor V. Batyrev,
33
"Dual polyhedra and mirror symmetry for Calabi-Yau hypersurfaces in toric
34
varieties",
35
J. Algebraic Geom. 3 (1994), no. 3, 493-535.
36
arXiv:alg-geom/9310003v1
37
38
.. [Borisov1993]
39
Lev A. Borisov,
40
"Towards the mirror symmetry for Calabi-Yau complete intersections in
41
Gorenstein Fano toric varieties", 1993.
42
arXiv:alg-geom/9310001v1
43
44
.. [CD2007]
45
Adrian Clingher and Charles F. Doran,
46
"Modular invariants for lattice polarized K3 surfaces",
47
Michigan Math. J. 55 (2007), no. 2, 355-393.
48
arXiv:math/0602146v1 [math.AG]
49
50
.. [Nill2005]
51
Benjamin Nill,
52
"Gorenstein toric Fano varieties",
53
Manuscripta Math. 116 (2005), no. 2, 183-210.
54
arXiv:math/0405448v1 [math.AG]
55
56
AUTHORS:
57
58
- Andrey Novoseltsev (2010-05-18): initial version.
59
60
EXAMPLES:
61
62
Most of the functions available for Fano toric varieties are the same as
63
for general toric varieties, so here we will concentrate only on
64
Calabi-Yau subvarieties, which were the primary goal for creating this
65
module.
66
67
For our first example we realize the projective plane as a Fano toric
68
variety::
69
70
sage: simplex = lattice_polytope.projective_space(2)
71
sage: P2 = CPRFanoToricVariety(Delta_polar=simplex)
72
73
Its anticanonical "hypersurface" is a one-dimensional Calabi-Yau
74
manifold::
75
76
sage: P2.anticanonical_hypersurface(
77
... monomial_points="all")
78
Closed subscheme of 2-d CPR-Fano toric variety
79
covered by 3 affine patches defined by:
80
a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2
81
+ a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2
82
+ a4*z1^2*z2 + a5*z0*z2^2
83
+ a3*z1*z2^2 + a2*z2^3
84
85
In many cases it is sufficient to work with the "simplified polynomial
86
moduli space" of anticanonical hypersurfaces::
87
88
sage: P2.anticanonical_hypersurface(
89
... monomial_points="simplified")
90
Closed subscheme of 2-d CPR-Fano toric variety
91
covered by 3 affine patches defined by:
92
a0*z0^3 + a1*z1^3 + a6*z0*z1*z2 + a2*z2^3
93
94
The mirror family to these hypersurfaces lives inside the Fano toric
95
variety obtained using ``simplex`` as ``Delta`` instead of ``Delta_polar``::
96
97
sage: FTV = CPRFanoToricVariety(Delta=simplex,
98
... coordinate_points="all")
99
sage: FTV.anticanonical_hypersurface(
100
... monomial_points="simplified")
101
Closed subscheme of 2-d CPR-Fano toric variety
102
covered by 9 affine patches defined by:
103
a2*z2^3*z3^2*z4*z5^2*z8
104
+ a1*z1^3*z3*z4^2*z7^2*z9
105
+ a3*z0*z1*z2*z3*z4*z5*z7*z8*z9
106
+ a0*z0^3*z5*z7*z8^2*z9^2
107
108
Here we have taken the resolved version of the ambient space for the
109
mirror family, but in fact we don't have to resolve singularities
110
corresponding to the interior points of facets - they are singular
111
points which do not lie on a generic anticanonical hypersurface::
112
113
sage: FTV = CPRFanoToricVariety(Delta=simplex,
114
... coordinate_points="all but facets")
115
sage: FTV.anticanonical_hypersurface(
116
... monomial_points="simplified")
117
Closed subscheme of 2-d CPR-Fano toric variety
118
covered by 3 affine patches defined by:
119
a0*z0^3 + a1*z1^3 + a3*z0*z1*z2 + a2*z2^3
120
121
This looks very similar to our second version of the anticanonical
122
hypersurface of the projective plane, as expected, since all
123
one-dimensional Calabi-Yau manifolds are elliptic curves!
124
125
Now let's take a look at a toric realization of `M`-polarized K3 surfaces
126
studied by Adrian Clingher and Charles F. Doran in [CD2007]_::
127
128
sage: p4318 = ReflexivePolytope(3, 4318) # long time
129
sage: FTV = CPRFanoToricVariety(Delta_polar=p4318) # long time
130
sage: FTV.anticanonical_hypersurface() # long time
131
Closed subscheme of 3-d CPR-Fano toric variety
132
covered by 4 affine patches defined by:
133
a3*z2^12 + a4*z2^6*z3^6 + a2*z3^12
134
+ a8*z0*z1*z2*z3 + a0*z1^3 + a1*z0^2
135
136
Below you will find detailed descriptions of available functions. Current
137
functionality of this module is very basic, but it is under active
138
development and hopefully will improve in future releases of Sage. If there
139
are some particular features that you would like to see implemented ASAP,
140
please consider reporting them to the Sage Development Team or even
141
implementing them on your own as a patch for inclusion!
142
"""
143
# The first example of the tutorial is taken from
144
# CPRFanoToricVariety_field.anticanonical_hypersurface
145
146
147
#*****************************************************************************
148
# Copyright (C) 2010 Andrey Novoseltsev <[email protected]>
149
# Copyright (C) 2010 William Stein <[email protected]>
150
#
151
# Distributed under the terms of the GNU General Public License (GPL)
152
#
153
# http://www.gnu.org/licenses/
154
#*****************************************************************************
155
156
from sage.geometry.all import Cone, FaceFan, Fan, LatticePolytope
157
from sage.misc.all import latex, prod
158
from sage.rings.all import (PolynomialRing, QQ,
159
is_FractionField, is_Field,
160
is_MPolynomialRing, is_PolynomialRing)
161
from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme_toric
162
from sage.schemes.toric.variety import (
163
ToricVariety_field,
164
normalize_names)
165
from sage.symbolic.all import SR
166
167
168
# Default coefficient for anticanonical hypersurfaces
169
DEFAULT_COEFFICIENT = "a"
170
# Default coefficients for nef complete intersections
171
DEFAULT_COEFFICIENTS = tuple(chr(i) for i in range(ord("a"), ord("z") + 1))
172
173
174
def is_CPRFanoToricVariety(x):
175
r"""
176
Check if ``x`` is a CPR-Fano toric variety.
177
178
INPUT:
179
180
- ``x`` -- anything.
181
182
OUTPUT:
183
184
- ``True`` if ``x`` is a :class:`CPR-Fano toric variety
185
<CPRFanoToricVariety_field>` and ``False`` otherwise.
186
187
.. NOTE::
188
189
While projective spaces are Fano toric varieties mathematically, they
190
are not toric varieties in Sage due to efficiency considerations, so
191
this function will return ``False``.
192
193
EXAMPLES::
194
195
sage: from sage.schemes.toric.fano_variety import (
196
... is_CPRFanoToricVariety)
197
sage: is_CPRFanoToricVariety(1)
198
False
199
sage: FTV = CPRFanoToricVariety(lattice_polytope.octahedron(2))
200
sage: FTV
201
2-d CPR-Fano toric variety covered by 4 affine patches
202
sage: is_CPRFanoToricVariety(FTV)
203
True
204
sage: is_CPRFanoToricVariety(ProjectiveSpace(2))
205
False
206
"""
207
return isinstance(x, CPRFanoToricVariety_field)
208
209
210
def CPRFanoToricVariety(Delta=None,
211
Delta_polar=None,
212
coordinate_points=None,
213
charts=None,
214
coordinate_names=None,
215
names=None,
216
coordinate_name_indices=None,
217
make_simplicial=False,
218
base_field=None,
219
check=True):
220
r"""
221
Construct a CPR-Fano toric variety.
222
223
.. NOTE::
224
225
See documentation of the module
226
:mod:`~sage.schemes.toric.fano_variety` for the used
227
definitions and supported varieties.
228
229
Due to the large number of available options, it is recommended to always
230
use keyword parameters.
231
232
INPUT:
233
234
- ``Delta`` -- reflexive :class:`lattice polytope
235
<sage.geometry.lattice_polytope.LatticePolytopeClass>`. The fan of the
236
constructed CPR-Fano toric variety will be a crepant subdivision of the
237
*normal fan* of ``Delta``. Either ``Delta`` or ``Delta_polar`` must be
238
given, but not both at the same time, since one is completely determined
239
by another via :meth:`polar
240
<sage.geometry.lattice_polytope.LatticePolytopeClass.polar>` method;
241
242
- ``Delta_polar`` -- reflexive :class:`lattice polytope
243
<sage.geometry.lattice_polytope.LatticePolytopeClass>`. The fan of the
244
constructed CPR-Fano toric variety will be a crepant subdivision of the
245
*face fan* of ``Delta_polar``. Either ``Delta`` or ``Delta_polar`` must
246
be given, but not both at the same time, since one is completely
247
determined by another via :meth:`polar
248
<sage.geometry.lattice_polytope.LatticePolytopeClass.polar>` method;
249
250
- ``coordinate_points`` -- list of integers or string. A list will be
251
interpreted as indices of (boundary) points of ``Delta_polar`` which
252
should be used as rays of the underlying fan. It must include all
253
vertices of ``Delta_polar`` and no repetitions are allowed. A string
254
must be one of the following descriptions of points of ``Delta_polar``:
255
256
* "vertices" (default),
257
* "all" (will not include the origin),
258
* "all but facets" (will not include points in the relative interior of
259
facets);
260
261
- ``charts`` -- list of lists of elements from ``coordinate_points``. Each
262
of these lists must define a generating cone of a fan subdividing the
263
normal fan of ``Delta``. Default ``charts`` correspond to the normal fan
264
of ``Delta`` without subdivision. The fan specified by ``charts`` will
265
be subdivided to include all of the requested ``coordinate_points``;
266
267
- ``coordinate_names`` -- names of variables for the coordinate ring, see
268
:func:`~sage.schemes.toric.variety.normalize_names`
269
for acceptable formats. If not given, indexed variable names will be
270
created automatically;
271
272
- ``names`` -- an alias of ``coordinate_names`` for internal
273
use. You may specify either ``names`` or ``coordinate_names``,
274
but not both;
275
276
- ``coordinate_name_indices`` -- list of integers, indices for indexed
277
variables. If not given, the index of each variable will coincide with
278
the index of the corresponding point of ``Delta_polar``;
279
280
- ``make_simplicial`` -- if ``True``, the underlying fan will be made
281
simplicial (default: ``False``);
282
283
- ``base_field`` -- base field of the CPR-Fano toric variety
284
(default: `\QQ`);
285
286
- ``check`` -- by default the input data will be checked for correctness
287
(e.g. that ``charts`` do form a subdivision of the normal fan of
288
``Delta``). If you know for sure that the input is valid, you may
289
significantly decrease construction time using ``check=False`` option.
290
291
OUTPUT:
292
293
- :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`.
294
295
EXAMPLES:
296
297
We start with the product of two projective lines::
298
299
sage: diamond = lattice_polytope.octahedron(2)
300
sage: diamond.vertices()
301
[ 1 0 -1 0]
302
[ 0 1 0 -1]
303
sage: P1xP1 = CPRFanoToricVariety(Delta_polar=diamond)
304
sage: P1xP1
305
2-d CPR-Fano toric variety covered by 4 affine patches
306
sage: P1xP1.fan()
307
Rational polyhedral fan in 2-d lattice N
308
sage: P1xP1.fan().ray_matrix()
309
[ 1 0 -1 0]
310
[ 0 1 0 -1]
311
312
"Unfortunately," this variety is smooth to start with and we cannot
313
perform any subdivisions of the underlying fan without leaving the
314
category of CPR-Fano toric varieties. Our next example starts with a
315
square::
316
317
sage: square = diamond.polar()
318
sage: square.vertices()
319
[-1 1 -1 1]
320
[ 1 1 -1 -1]
321
sage: square.points()
322
[-1 1 -1 1 -1 0 0 0 1]
323
[ 1 1 -1 -1 0 -1 0 1 0]
324
325
We will construct several varieties associated to it::
326
327
sage: FTV = CPRFanoToricVariety(Delta_polar=square)
328
sage: FTV.fan().ray_matrix()
329
[-1 1 -1 1]
330
[ 1 1 -1 -1]
331
sage: FTV.gens()
332
(z0, z1, z2, z3)
333
334
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
335
... coordinate_points=[0,1,2,3,8])
336
sage: FTV.fan().ray_matrix()
337
[-1 1 -1 1 1]
338
[ 1 1 -1 -1 0]
339
sage: FTV.gens()
340
(z0, z1, z2, z3, z8)
341
342
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
343
... coordinate_points=[8,0,2,1,3],
344
... coordinate_names="x+")
345
sage: FTV.fan().ray_matrix()
346
[ 1 -1 -1 1 1]
347
[ 0 1 -1 1 -1]
348
sage: FTV.gens()
349
(x8, x0, x2, x1, x3)
350
351
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
352
... coordinate_points="all",
353
... coordinate_names="x y Z+")
354
sage: FTV.fan().ray_matrix()
355
[-1 1 -1 1 -1 0 0 1]
356
[ 1 1 -1 -1 0 -1 1 0]
357
sage: FTV.gens()
358
(x, y, Z2, Z3, Z4, Z5, Z7, Z8)
359
360
Note that ``Z6`` is "missing". This is due to the fact that the 6-th point
361
of ``square`` is the origin, and all automatically created names have the
362
same indices as corresponding points of
363
:meth:`~CPRFanoToricVariety_field.Delta_polar`. This is usually very
364
convenient, especially if you have to work with several partial
365
resolutions of the same Fano toric variety. However, you can change it, if
366
you want::
367
368
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
369
... coordinate_points="all",
370
... coordinate_names="x y Z+",
371
... coordinate_name_indices=range(8))
372
sage: FTV.gens()
373
(x, y, Z2, Z3, Z4, Z5, Z6, Z7)
374
375
Note that you have to provide indices for *all* variables, including those
376
that have "completely custom" names. Again, this is usually convenient,
377
because you can add or remove "custom" variables without disturbing too
378
much "automatic" ones::
379
380
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
381
... coordinate_points="all",
382
... coordinate_names="x Z+",
383
... coordinate_name_indices=range(8))
384
sage: FTV.gens()
385
(x, Z1, Z2, Z3, Z4, Z5, Z6, Z7)
386
387
If you prefer to always start from zero, you will have to shift indices
388
accordingly::
389
390
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
391
... coordinate_points="all",
392
... coordinate_names="x Z+",
393
... coordinate_name_indices=[0] + range(7))
394
sage: FTV.gens()
395
(x, Z0, Z1, Z2, Z3, Z4, Z5, Z6)
396
397
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
398
... coordinate_points="all",
399
... coordinate_names="x y Z+",
400
... coordinate_name_indices=[0]*2 + range(6))
401
sage: FTV.gens()
402
(x, y, Z0, Z1, Z2, Z3, Z4, Z5)
403
404
So you always can get any names you want, somewhat complicated default
405
behaviour was designed with the hope that in most cases you will have no
406
desire to provide different names.
407
408
Now we will use the possibility to specify initial charts::
409
410
sage: charts = [(0,1), (1,3), (3,2), (2,0)]
411
412
(these charts actually form exactly the face fan of our square) ::
413
414
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
415
... coordinate_points=[0,1,2,3,4],
416
... charts=charts)
417
sage: FTV.fan().ray_matrix()
418
[-1 1 -1 1 -1]
419
[ 1 1 -1 -1 0]
420
sage: [cone.ambient_ray_indices() for cone in FTV.fan()]
421
[(0, 1), (1, 3), (2, 3), (2, 4), (0, 4)]
422
423
If charts are wrong, it should be detected::
424
425
sage: bad_charts = charts + [(2,0)]
426
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
427
... coordinate_points=[0,1,2,3,4],
428
... charts=bad_charts)
429
Traceback (most recent call last):
430
...
431
ValueError: you have provided 5 cones, but only 4 of them are maximal!
432
Use discard_faces=True if you indeed need to construct a fan from
433
these cones.
434
435
These charts are technically correct, they just happened to list one of
436
them twice, but it is assumed that such a situation will not happen. It is
437
especially important when you try to speed up your code::
438
439
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
440
... coordinate_points=[0,1,2,3,4],
441
... charts=bad_charts,
442
... check=False)
443
sage: FTV.fan().ray_matrix()
444
[-1 1 -1 1 -1]
445
[ 1 1 -1 -1 0]
446
sage: [cone.ambient_ray_indices() for cone in FTV.fan()]
447
[(0, 1), (1, 3), (2, 3), (2, 4), (0, 4), (2, 4), (0, 4)]
448
449
The last line shows two of the generating cones twice. While "everything
450
still works" in the sense "it does not crash," any work with such a
451
variety may lead to mathematically wrong results, so use ``check=False``
452
carefully!
453
454
Here are some other possible mistakes::
455
456
sage: bad_charts = charts + [(0,3)]
457
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
458
... coordinate_points=[0,1,2,3,4],
459
... charts=bad_charts)
460
Traceback (most recent call last):
461
...
462
ValueError: (0, 3) does not form a chart of a
463
subdivision of the face fan of A polytope polar
464
to An octahedron: 2-dimensional, 4 vertices.!
465
466
sage: bad_charts = charts[:-1]
467
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
468
... coordinate_points=[0,1,2,3,4],
469
... charts=bad_charts)
470
Traceback (most recent call last):
471
...
472
ValueError: given charts do not form a complete fan!
473
474
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
475
... coordinate_points=[1,2,3,4])
476
Traceback (most recent call last):
477
...
478
ValueError: all 4 vertices of Delta_polar
479
must be used for coordinates!
480
Got: [1, 2, 3, 4]
481
482
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
483
... coordinate_points=[0,0,1,2,3,4])
484
Traceback (most recent call last):
485
...
486
ValueError: no repetitions are
487
allowed for coordinate points!
488
Got: [0, 0, 1, 2, 3, 4]
489
490
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
491
... coordinate_points=[0,1,2,3,6])
492
Traceback (most recent call last):
493
...
494
ValueError: the origin (point #6)
495
cannot be used for a coordinate!
496
Got: [0, 1, 2, 3, 6]
497
498
Here is a shorthand for defining the toric variety and homogeneous
499
coordinates in one go::
500
501
sage: P1xP1.<a,b,c,d> = CPRFanoToricVariety(Delta_polar=diamond)
502
sage: (a^2+b^2) * (c+d)
503
a^2*c + b^2*c + a^2*d + b^2*d
504
"""
505
if names is not None:
506
if coordinate_names is not None:
507
raise ValueError('You must not specify both coordinate_names and names!')
508
coordinate_names = names
509
# Check/normalize Delta_polar
510
if Delta is None and Delta_polar is None:
511
raise ValueError("either Delta or Delta_polar must be given!")
512
elif Delta is not None and Delta_polar is not None:
513
raise ValueError("Delta and Delta_polar cannot be given together!")
514
elif Delta_polar is None:
515
Delta_polar = Delta.polar()
516
elif not Delta_polar.is_reflexive():
517
raise ValueError("Delta_polar must be reflexive!")
518
# Check/normalize coordinate_points and construct fan rays
519
if coordinate_points is None:
520
coordinate_points = range(Delta_polar.nvertices())
521
if charts is not None:
522
for chart in charts:
523
for point in chart:
524
if point not in coordinate_points:
525
coordinate_points.append(point)
526
elif coordinate_points == "vertices":
527
coordinate_points = range(Delta_polar.nvertices())
528
elif coordinate_points == "all":
529
coordinate_points = range(Delta_polar.npoints())
530
coordinate_points.remove(Delta_polar.origin())
531
elif coordinate_points == "all but facets":
532
coordinate_points = Delta_polar.skeleton_points(Delta_polar.dim() - 2)
533
elif isinstance(coordinate_points, str):
534
raise ValueError("unrecognized description of the coordinate points!"
535
"\nGot: %s" % coordinate_points)
536
elif check:
537
cp_set = set(coordinate_points)
538
if len(cp_set) != len(coordinate_points):
539
raise ValueError(
540
"no repetitions are allowed for coordinate points!\nGot: %s"
541
% coordinate_points)
542
if not cp_set.issuperset(range(Delta_polar.nvertices())):
543
raise ValueError("all %d vertices of Delta_polar must be used "
544
"for coordinates!\nGot: %s"
545
% (Delta_polar.nvertices(), coordinate_points))
546
if Delta_polar.origin() in cp_set:
547
raise ValueError("the origin (point #%d) cannot be used for a "
548
"coordinate!\nGot: %s"
549
% (Delta_polar.origin(), coordinate_points))
550
point_to_ray = dict()
551
for n, point in enumerate(coordinate_points):
552
point_to_ray[point] = n
553
# This can be simplified if LatticePolytopeClass is adjusted.
554
rays = [Delta_polar.point(p) for p in coordinate_points]
555
for ray in rays:
556
ray.set_immutable()
557
# Check/normalize charts and construct the fan based on them.
558
if charts is None:
559
# Start with the face fan
560
fan = FaceFan(Delta_polar)
561
else:
562
# First of all, check that each chart is completely contained in a
563
# single facet of Delta_polar, otherwise they do not form a
564
# subdivision of the face fan of Delta_polar
565
if check:
566
facet_sets = [frozenset(facet.points())
567
for facet in Delta_polar.facets()]
568
for chart in charts:
569
is_bad = True
570
for fset in facet_sets:
571
if fset.issuperset(chart):
572
is_bad = False
573
break
574
if is_bad:
575
raise ValueError(
576
"%s does not form a chart of a subdivision of the "
577
"face fan of %s!" % (chart, Delta_polar))
578
# We will construct the initial fan from Cone objects: since charts
579
# may not use all of the necessary rays, alternative form is tedious
580
# With check=False it should not be long anyway.
581
cones = [Cone((rays[point_to_ray[point]] for point in chart),
582
check=check)
583
for chart in charts]
584
fan = Fan(cones, check=check)
585
if check and not fan.is_complete():
586
raise ValueError("given charts do not form a complete fan!")
587
# Subdivide this fan to use all required points
588
fan = fan.subdivide(new_rays=(ray for ray in rays
589
if ray not in fan.ray_set()),
590
make_simplicial=make_simplicial)
591
# Now create yet another fan making sure that the order of the rays is
592
# the same as requested (it is a bit difficult to get it from the start)
593
trans = dict()
594
for n, ray in enumerate(fan.rays()):
595
trans[n] = rays.index(ray)
596
cones = tuple(tuple(sorted(trans[r] for r in cone.ambient_ray_indices()))
597
for cone in fan)
598
fan = Fan(cones, rays, check=False)
599
# Check/normalize base_field
600
if base_field is None:
601
base_field = QQ
602
elif not is_Field(base_field):
603
raise TypeError("need a field to construct a Fano toric variety!"
604
"\n Got %s" % base_field)
605
fan._is_complete = True # At this point it must be for sure
606
return CPRFanoToricVariety_field(Delta_polar, fan, coordinate_points,
607
point_to_ray, coordinate_names, coordinate_name_indices, base_field)
608
609
610
class CPRFanoToricVariety_field(ToricVariety_field):
611
r"""
612
Construct a CPR-Fano toric variety associated to a reflexive polytope.
613
614
.. WARNING::
615
616
This class does not perform any checks of correctness of input and it
617
does assume that the internal structure of the given parameters is
618
coordinated in a certain way. Use
619
:func:`CPRFanoToricVariety` to construct CPR-Fano toric varieties.
620
621
.. NOTE::
622
623
See documentation of the module
624
:mod:`~sage.schemes.toric.fano_variety` for the used
625
definitions and supported varieties.
626
627
INPUT:
628
629
- ``Delta_polar`` -- reflexive polytope;
630
631
- ``fan`` -- rational polyhedral fan subdividing the face fan of
632
``Delta_polar``;
633
634
- ``coordinate_points`` -- list of indices of points of ``Delta_polar``
635
used for rays of ``fan``;
636
637
- ``point_to_ray`` -- dictionary mapping the index of a coordinate point
638
to the index of the corresponding ray;
639
640
- ``coordinate_names`` -- names of the variables of the coordinate ring in
641
the format accepted by
642
:func:`~sage.schemes.toric.variety.normalize_names`;
643
644
- ``coordinate_name_indices`` -- indices for indexed variables,
645
if ``None``, will be equal to ``coordinate_points``;
646
647
- ``base_field`` -- base field of the CPR-Fano toric variety.
648
649
OUTPUT:
650
651
- :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>`.
652
653
TESTS::
654
655
sage: P1xP1 = CPRFanoToricVariety(
656
... Delta_polar=lattice_polytope.octahedron(2))
657
sage: P1xP1
658
2-d CPR-Fano toric variety covered by 4 affine patches
659
"""
660
661
def __init__(self, Delta_polar, fan, coordinate_points, point_to_ray,
662
coordinate_names, coordinate_name_indices, base_field):
663
r"""
664
See :class:`CPRFanoToricVariety_field` for documentation.
665
666
Use ``CPRFanoToricVariety`` to construct CPR-Fano toric varieties.
667
668
TESTS::
669
670
sage: P1xP1 = CPRFanoToricVariety(
671
... Delta_polar=lattice_polytope.octahedron(2))
672
sage: P1xP1
673
2-d CPR-Fano toric variety covered by 4 affine patches
674
"""
675
self._Delta_polar = Delta_polar
676
self._coordinate_points = tuple(coordinate_points)
677
self._point_to_ray = point_to_ray
678
# Check/normalize coordinate_indices
679
if coordinate_name_indices is None:
680
coordinate_name_indices = coordinate_points
681
super(CPRFanoToricVariety_field, self).__init__(fan, coordinate_names,
682
coordinate_name_indices, base_field)
683
684
def _latex_(self):
685
r"""
686
Return a LaTeX representation of ``self``.
687
688
OUTPUT:
689
690
- string.
691
692
TESTS::
693
694
sage: P1xP1 = CPRFanoToricVariety(
695
... Delta_polar=lattice_polytope.octahedron(2))
696
sage: P1xP1._latex_()
697
'\\mathbb{P}_{\\Delta^{2}}'
698
"""
699
return r"\mathbb{P}_{%s}" % latex(self.Delta())
700
701
def _repr_(self):
702
r"""
703
Return a string representation of ``self``.
704
705
OUTPUT:
706
707
- string.
708
709
TESTS::
710
711
sage: P1xP1 = CPRFanoToricVariety(
712
... Delta_polar=lattice_polytope.octahedron(2))
713
sage: P1xP1._repr_()
714
'2-d CPR-Fano toric variety covered by 4 affine patches'
715
"""
716
return ("%d-d CPR-Fano toric variety covered by %d affine patches"
717
% (self.dimension_relative(), self.fan().ngenerating_cones()))
718
719
def anticanonical_hypersurface(self, **kwds):
720
r"""
721
Return an anticanonical hypersurface of ``self``.
722
723
.. NOTE::
724
725
The returned hypersurface may be actually a subscheme of
726
**another** CPR-Fano toric variety: if the base field of ``self``
727
does not include all of the required names for generic monomial
728
coefficients, it will be automatically extended.
729
730
Below `\Delta` is the reflexive polytope corresponding to ``self``,
731
i.e. the fan of ``self`` is a refinement of the normal fan of
732
`\Delta`. This function accepts only keyword parameters.
733
734
INPUT:
735
736
- ``monomial points`` -- a list of integers or a string. A list will be
737
interpreted as indices of points of `\Delta` which should be used
738
for monomials of this hypersurface. A string must be one of the
739
following descriptions of points of `\Delta`:
740
741
* "vertices",
742
* "vertices+origin",
743
* "all",
744
* "simplified" (default) -- all points of `\Delta` except for
745
the interior points of facets, this choice corresponds to working
746
with the "simplified polynomial moduli space" of anticanonical
747
hypersurfaces;
748
749
- ``coefficient_names`` -- names for the monomial coefficients, see
750
:func:`~sage.schemes.toric.variety.normalize_names`
751
for acceptable formats. If not given, indexed coefficient names will
752
be created automatically;
753
754
- ``coefficient_name_indices`` -- a list of integers, indices for
755
indexed coefficients. If not given, the index of each coefficient
756
will coincide with the index of the corresponding point of `\Delta`;
757
758
- ``coefficients`` -- as an alternative to specifying coefficient
759
names and/or indices, you can give the coefficients themselves as a
760
list of rational functions. If you do it, then the base field of
761
``self`` will be extended to include all necessary names. Each of
762
these rational functions can be given by any expression that can be
763
converted to a symbolic ring, e.g. strings.
764
765
OUTPUT:
766
767
- an :class:`anticanonical hypersurface <AnticanonicalHypersurface>` of
768
``self`` (with the extended base field, if necessary).
769
770
EXAMPLES:
771
772
We realize the projective plane as a Fano toric variety::
773
774
sage: simplex = lattice_polytope.projective_space(2)
775
sage: P2 = CPRFanoToricVariety(Delta_polar=simplex)
776
777
Its anticanonical "hypersurface" is a one-dimensional Calabi-Yau
778
manifold::
779
780
sage: P2.anticanonical_hypersurface(
781
... monomial_points="all")
782
Closed subscheme of 2-d CPR-Fano toric variety
783
covered by 3 affine patches defined by:
784
a0*z0^3 + a9*z0^2*z1 + a7*z0*z1^2
785
+ a1*z1^3 + a8*z0^2*z2 + a6*z0*z1*z2
786
+ a4*z1^2*z2 + a5*z0*z2^2
787
+ a3*z1*z2^2 + a2*z2^3
788
789
In many cases it is sufficient to work with the "simplified polynomial
790
moduli space" of anticanonical hypersurfaces::
791
792
sage: P2.anticanonical_hypersurface(
793
... monomial_points="simplified")
794
Closed subscheme of 2-d CPR-Fano toric variety
795
covered by 3 affine patches defined by:
796
a0*z0^3 + a1*z1^3 + a6*z0*z1*z2 + a2*z2^3
797
798
The mirror family to these hypersurfaces lives inside the Fano toric
799
variety obtained using ``simplex`` as ``Delta`` instead of
800
``Delta_polar``::
801
802
sage: FTV = CPRFanoToricVariety(Delta=simplex,
803
... coordinate_points="all")
804
sage: FTV.anticanonical_hypersurface(
805
... monomial_points="simplified")
806
Closed subscheme of 2-d CPR-Fano toric variety
807
covered by 9 affine patches defined by:
808
a2*z2^3*z3^2*z4*z5^2*z8
809
+ a1*z1^3*z3*z4^2*z7^2*z9
810
+ a3*z0*z1*z2*z3*z4*z5*z7*z8*z9
811
+ a0*z0^3*z5*z7*z8^2*z9^2
812
813
Here we have taken the resolved version of the ambient space for the
814
mirror family, but in fact we don't have to resolve singularities
815
corresponding to the interior points of facets - they are singular
816
points which do not lie on a generic anticanonical hypersurface::
817
818
sage: FTV = CPRFanoToricVariety(Delta=simplex,
819
... coordinate_points="all but facets")
820
sage: FTV.anticanonical_hypersurface(
821
... monomial_points="simplified")
822
Closed subscheme of 2-d CPR-Fano toric variety
823
covered by 3 affine patches defined by:
824
a0*z0^3 + a1*z1^3 + a3*z0*z1*z2 + a2*z2^3
825
826
This looks very similar to our second anticanonical
827
hypersurface of the projective plane, as expected, since all
828
one-dimensional Calabi-Yau manifolds are elliptic curves!
829
830
All anticanonical hypersurfaces constructed above were generic with
831
automatically generated coefficients. If you want, you can specify your
832
own names ::
833
834
sage: FTV.anticanonical_hypersurface(
835
... coefficient_names="a b c d")
836
Closed subscheme of 2-d CPR-Fano toric variety
837
covered by 3 affine patches defined by:
838
a*z0^3 + b*z1^3 + d*z0*z1*z2 + c*z2^3
839
840
or give concrete coefficients ::
841
842
sage: FTV.anticanonical_hypersurface(
843
... coefficients=[1, 2, 3, 4])
844
Closed subscheme of 2-d CPR-Fano toric variety
845
covered by 3 affine patches defined by:
846
z0^3 + 2*z1^3 + 4*z0*z1*z2 + 3*z2^3
847
848
or even mix numerical coefficients with some expressions ::
849
850
sage: var("t")
851
t
852
sage: H = FTV.anticanonical_hypersurface(
853
... coefficients=[0, t, 1/t, "psi/(psi^2 + phi)"])
854
sage: H
855
Closed subscheme of 2-d CPR-Fano toric variety
856
covered by 3 affine patches defined by:
857
t*z1^3 + (psi/(psi^2 + phi))*z0*z1*z2 + 1/t*z2^3
858
sage: R = H.ambient_space().base_ring()
859
sage: R
860
Fraction Field of
861
Multivariate Polynomial Ring in t, phi, psi
862
over Rational Field
863
864
Note that ``t`` in the base ring of the last example is **not** the
865
same as the symbolic variable ``t`` used for specifying coefficients::
866
867
sage: R.gen(0)
868
t
869
sage: R.gen(0) is t
870
False
871
"""
872
# The example above is also copied to the tutorial section in the
873
# main documentation of the module.
874
return AnticanonicalHypersurface(self, **kwds)
875
876
def change_ring(self, F):
877
r"""
878
Return a CPR-Fano toric variety over field ``F``, otherwise the same
879
as ``self``.
880
881
INPUT:
882
883
- ``F`` -- field.
884
885
OUTPUT:
886
887
- :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>` over
888
``F``.
889
890
.. NOTE::
891
892
There is no need to have any relation between ``F`` and the base
893
field of ``self``. If you do want to have such a relation, use
894
:meth:`base_extend` instead.
895
896
EXAMPLES::
897
898
sage: P1xP1 = CPRFanoToricVariety(
899
... Delta_polar=lattice_polytope.octahedron(2))
900
sage: P1xP1.base_ring()
901
Rational Field
902
sage: P1xP1_RR = P1xP1.change_ring(RR)
903
sage: P1xP1_RR.base_ring()
904
Real Field with 53 bits of precision
905
sage: P1xP1_QQ = P1xP1_RR.change_ring(QQ)
906
sage: P1xP1_QQ.base_ring()
907
Rational Field
908
sage: P1xP1_RR.base_extend(QQ)
909
Traceback (most recent call last):
910
...
911
ValueError: no natural map from the base ring
912
(=Real Field with 53 bits of precision)
913
to R (=Rational Field)!
914
"""
915
if self.base_ring() == F:
916
return self
917
else:
918
return CPRFanoToricVariety_field(self._Delta_polar, self._fan,
919
self._coordinate_points, self._point_to_ray,
920
self.variable_names(), None, F)
921
# coordinate_name_indices do not matter, we give explicit
922
# names for all variables
923
924
def coordinate_point_to_coordinate(self, point):
925
r"""
926
Return the variable of the coordinate ring corresponding to ``point``.
927
928
INPUT:
929
930
- ``point`` -- integer from the list of :meth:`coordinate_points`.
931
932
OUTPUT:
933
934
- the corresponding generator of the coordinate ring of ``self``.
935
936
EXAMPLES::
937
938
sage: diamond = lattice_polytope.octahedron(2)
939
sage: FTV = CPRFanoToricVariety(diamond,
940
... coordinate_points=[0,1,2,3,8])
941
sage: FTV.coordinate_points()
942
(0, 1, 2, 3, 8)
943
sage: FTV.gens()
944
(z0, z1, z2, z3, z8)
945
sage: FTV.coordinate_point_to_coordinate(8)
946
z8
947
"""
948
return self.gen(self._point_to_ray[point])
949
950
def coordinate_points(self):
951
r"""
952
Return indices of points of :meth:`Delta_polar` used for coordinates.
953
954
OUTPUT:
955
956
- :class:`tuple` of integers.
957
958
EXAMPLES::
959
960
sage: diamond = lattice_polytope.octahedron(2)
961
sage: square = diamond.polar()
962
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
963
... coordinate_points=[0,1,2,3,8])
964
sage: FTV.coordinate_points()
965
(0, 1, 2, 3, 8)
966
sage: FTV.gens()
967
(z0, z1, z2, z3, z8)
968
969
sage: FTV = CPRFanoToricVariety(Delta_polar=square,
970
... coordinate_points="all")
971
sage: FTV.coordinate_points()
972
(0, 1, 2, 3, 4, 5, 7, 8)
973
sage: FTV.gens()
974
(z0, z1, z2, z3, z4, z5, z7, z8)
975
976
Note that one point is missing, namely ::
977
978
sage: square.origin()
979
6
980
"""
981
return self._coordinate_points
982
983
def Delta(self):
984
r"""
985
Return the reflexive polytope associated to ``self``.
986
987
OUTPUT:
988
989
- reflexive :class:`lattice polytope
990
<sage.geometry.lattice_polytope.LatticePolytopeClass>`. The
991
underlying fan of ``self`` is a coherent subdivision of the
992
*normal fan* of this polytope.
993
994
EXAMPLES::
995
996
sage: diamond = lattice_polytope.octahedron(2)
997
sage: P1xP1 = CPRFanoToricVariety(Delta_polar=diamond)
998
sage: P1xP1.Delta()
999
A polytope polar to An octahedron: 2-dimensional, 4 vertices.
1000
sage: P1xP1.Delta() is diamond.polar()
1001
True
1002
"""
1003
return self._Delta_polar.polar()
1004
1005
def Delta_polar(self):
1006
r"""
1007
Return polar of :meth:`Delta`.
1008
1009
OUTPUT:
1010
1011
- reflexive :class:`lattice polytope
1012
<sage.geometry.lattice_polytope.LatticePolytopeClass>`. The
1013
underlying fan of ``self`` is a coherent subdivision of the
1014
*face fan* of this polytope.
1015
1016
EXAMPLES::
1017
1018
sage: diamond = lattice_polytope.octahedron(2)
1019
sage: P1xP1 = CPRFanoToricVariety(Delta_polar=diamond)
1020
sage: P1xP1.Delta_polar()
1021
An octahedron: 2-dimensional, 4 vertices.
1022
sage: P1xP1.Delta_polar() is diamond
1023
True
1024
sage: P1xP1.Delta_polar() is P1xP1.Delta().polar()
1025
True
1026
"""
1027
return self._Delta_polar
1028
1029
def nef_complete_intersection(self, nef_partition, **kwds):
1030
r"""
1031
Return a nef complete intersection in ``self``.
1032
1033
.. NOTE::
1034
1035
The returned complete intersection may be actually a subscheme of
1036
**another** CPR-Fano toric variety: if the base field of ``self``
1037
does not include all of the required names for monomial
1038
coefficients, it will be automatically extended.
1039
1040
Below `\Delta` is the reflexive polytope corresponding to ``self``,
1041
i.e. the fan of ``self`` is a refinement of the normal fan of
1042
`\Delta`. Other polytopes are described in the documentation of
1043
:class:`nef-partitions <sage.geometry.lattice_polytope.NefPartition>`
1044
of :class:`reflexive polytopes
1045
<sage.geometry.lattice_polytope.LatticePolytopeClass>`.
1046
1047
Except for the first argument, ``nef_partition``, this method accepts
1048
only keyword parameters.
1049
1050
INPUT:
1051
1052
- ``nef_partition`` -- a `k`-part :class:`nef-partition
1053
<sage.geometry.lattice_polytope.NefPartition>` of `\Delta^\circ`, all
1054
other parameters (if given) must be lists of length `k`;
1055
1056
- ``monomial_points`` -- the `i`-th element of this list is either a
1057
list of integers or a string. A list will be interpreted as indices
1058
of points of `\Delta_i` which should be used for monomials of the
1059
`i`-th polynomial of this complete intersection. A string must be one
1060
of the following descriptions of points of `\Delta_i`:
1061
1062
* "vertices",
1063
* "vertices+origin",
1064
* "all" (default),
1065
1066
when using this description, it is also OK to pass a single string as
1067
``monomial_points`` instead of repeating it `k` times;
1068
1069
- ``coefficient_names`` -- the `i`-th element of this list specifies
1070
names for the monomial coefficients of the `i`-th polynomial, see
1071
:func:`~sage.schemes.toric.variety.normalize_names`
1072
for acceptable formats. If not given, indexed coefficient names will
1073
be created automatically;
1074
1075
- ``coefficient_name_indices`` -- the `i`-th element of this list
1076
specifies indices for indexed coefficients of the `i`-th polynomial.
1077
If not given, the index of each coefficient will coincide with the
1078
index of the corresponding point of `\Delta_i`;
1079
1080
- ``coefficients`` -- as an alternative to specifying coefficient
1081
names and/or indices, you can give the coefficients themselves as
1082
rational functions. If you do it, then the base field of ``self``
1083
will be extended to include all necessary names. Each of these
1084
rational functions can be given by any expression that can be
1085
converted to a symbolic ring, e.g. strings.
1086
1087
OUTPUT:
1088
1089
- a :class:`nef complete intersection <NefCompleteIntersection>` of
1090
``self`` (with the extended base field, if necessary).
1091
1092
EXAMPLES:
1093
1094
We construct several complete intersections associated to the same
1095
nef-partition of the 3-dimensional reflexive polytope #2254::
1096
1097
sage: p = ReflexivePolytope(3, 2254) # long time (7s on sage.math, 2011)
1098
sage: np = p.nef_partitions()[1] # long time
1099
sage: np # long time
1100
Nef-partition {2, 3, 4, 7, 8} U {0, 1, 5, 6}
1101
sage: X = CPRFanoToricVariety(Delta_polar=p) # long time
1102
sage: X.nef_complete_intersection(np) # long time
1103
Closed subscheme of 3-d CPR-Fano toric variety
1104
covered by 10 affine patches defined by:
1105
a2*z1*z4^2*z5^2*z7^3 + a1*z2*z4*z5*z6*z7^2*z8^2
1106
+ a3*z2*z3*z4*z7*z8 + a0*z0*z2,
1107
b2*z1*z4*z5^2*z6^2*z7^2*z8^2 + b0*z2*z5*z6^3*z7*z8^4
1108
+ b5*z1*z3*z4*z5*z6*z7*z8 + b3*z2*z3*z6^2*z8^3
1109
+ b1*z1*z3^2*z4 + b4*z0*z1*z5*z6
1110
1111
Now we include only monomials associated to vertices of `\Delta_i`::
1112
1113
sage: X.nef_complete_intersection(np, monomial_points="vertices") # long time
1114
Closed subscheme of 3-d CPR-Fano toric variety
1115
covered by 10 affine patches defined by:
1116
a2*z1*z4^2*z5^2*z7^3 + a1*z2*z4*z5*z6*z7^2*z8^2
1117
+ a3*z2*z3*z4*z7*z8 + a0*z0*z2,
1118
b2*z1*z4*z5^2*z6^2*z7^2*z8^2 + b0*z2*z5*z6^3*z7*z8^4
1119
+ b3*z2*z3*z6^2*z8^3 + b1*z1*z3^2*z4 + b4*z0*z1*z5*z6
1120
1121
(effectively, we set ``b5=0``). Next we provide coefficients explicitly
1122
instead of using default generic names::
1123
1124
sage: X.nef_complete_intersection(np, # long time
1125
... monomial_points="vertices",
1126
... coefficients=[range(1,5), range(1,6)])
1127
Closed subscheme of 3-d CPR-Fano toric variety
1128
covered by 10 affine patches defined by:
1129
3*z1*z4^2*z5^2*z7^3 + 2*z2*z4*z5*z6*z7^2*z8^2
1130
+ 4*z2*z3*z4*z7*z8 + z0*z2,
1131
3*z1*z4*z5^2*z6^2*z7^2*z8^2 + z2*z5*z6^3*z7*z8^4
1132
+ 4*z2*z3*z6^2*z8^3 + 2*z1*z3^2*z4 + 5*z0*z1*z5*z6
1133
1134
Finally, we take a look at the generic representative of these complete
1135
intersections in a completely resolved ambient toric variety::
1136
1137
sage: X = CPRFanoToricVariety(Delta_polar=p, # long time
1138
... coordinate_points="all")
1139
sage: X.nef_complete_intersection(np) # long time
1140
Closed subscheme of 3-d CPR-Fano toric variety
1141
covered by 22 affine patches defined by:
1142
a1*z2*z4*z5*z6*z7^2*z8^2*z9^2*z10^2*z11*z12*z13
1143
+ a2*z1*z4^2*z5^2*z7^3*z9*z10^2*z12*z13
1144
+ a3*z2*z3*z4*z7*z8*z9*z10*z11*z12 + a0*z0*z2,
1145
b0*z2*z5*z6^3*z7*z8^4*z9^3*z10^2*z11^2*z12*z13^2
1146
+ b2*z1*z4*z5^2*z6^2*z7^2*z8^2*z9^2*z10^2*z11*z12*z13^2
1147
+ b3*z2*z3*z6^2*z8^3*z9^2*z10*z11^2*z12*z13
1148
+ b5*z1*z3*z4*z5*z6*z7*z8*z9*z10*z11*z12*z13
1149
+ b1*z1*z3^2*z4*z11*z12 + b4*z0*z1*z5*z6*z13
1150
"""
1151
return NefCompleteIntersection(self, nef_partition, **kwds)
1152
1153
def cartesian_product(self, other,
1154
coordinate_names=None, coordinate_indices=None):
1155
r"""
1156
Return the Cartesian product of ``self`` with ``other``.
1157
1158
INPUT:
1159
1160
- ``other`` -- a (possibly
1161
:class:`CPR-Fano <CPRFanoToricVariety_field>`) :class:`toric variety
1162
<sage.schemes.toric.variety.ToricVariety_field>`;
1163
1164
- ``coordinate_names`` -- names of variables for the coordinate ring,
1165
see :func:`normalize_names` for acceptable formats. If not given,
1166
indexed variable names will be created automatically;
1167
1168
- ``coordinate_indices`` -- list of integers, indices for indexed
1169
variables. If not given, the index of each variable will coincide
1170
with the index of the corresponding ray of the fan.
1171
1172
OUTPUT:
1173
1174
- a :class:`toric variety
1175
<sage.schemes.toric.variety.ToricVariety_field>`, which is
1176
:class:`CPR-Fano <CPRFanoToricVariety_field>` if ``other`` was.
1177
1178
EXAMPLES::
1179
1180
sage: P1 = toric_varieties.P1()
1181
sage: P2 = toric_varieties.P2()
1182
sage: P1xP2 = P1.cartesian_product(P2); P1xP2
1183
3-d CPR-Fano toric variety covered by 6 affine patches
1184
sage: P1xP2.fan().rays()
1185
(N+N(1, 0, 0), N+N(-1, 0, 0),
1186
N+N(0, 1, 0), N+N(0, 0, 1), N+N(0, -1, -1))
1187
sage: P1xP2.Delta_polar()
1188
A lattice polytope: 3-dimensional, 5 vertices.
1189
"""
1190
if is_CPRFanoToricVariety(other):
1191
fan = self.fan().cartesian_product(other.fan())
1192
Delta_polar = LatticePolytope(fan.rays())
1193
1194
points = Delta_polar.points().columns()
1195
point_to_ray = dict()
1196
coordinate_points = []
1197
for ray_index, ray in enumerate(fan.rays()):
1198
point = points.index(ray)
1199
coordinate_points.append(point)
1200
point_to_ray[point] = ray_index
1201
1202
return CPRFanoToricVariety_field(Delta_polar, fan,
1203
coordinate_points, point_to_ray,
1204
coordinate_names, coordinate_indices,
1205
self.base_ring())
1206
return super(CPRFanoToricVariety_field, self).cartesian_product(other)
1207
1208
def resolve(self, **kwds):
1209
r"""
1210
Construct a toric variety whose fan subdivides the fan of ``self``.
1211
1212
This function accepts only keyword arguments, none of which are
1213
mandatory.
1214
1215
INPUT:
1216
1217
- ``new_points`` -- list of integers, indices of boundary points of
1218
:meth:`Delta_polar`, which should be added as rays to the
1219
subdividing fan;
1220
1221
- all other arguments will be passed to
1222
:meth:`~sage.schemes.toric.variety.ToricVariety_field.resolve`
1223
method of (general) toric varieties, see its documentation for
1224
details.
1225
1226
OUTPUT:
1227
1228
- :class:`CPR-Fano toric variety <CPRFanoToricVariety_field>` if there
1229
was no ``new_rays`` argument and :class:`toric variety
1230
<sage.schemes.toric.variety.ToricVariety_field>` otherwise.
1231
1232
EXAMPLES::
1233
1234
sage: diamond = lattice_polytope.octahedron(2)
1235
sage: FTV = CPRFanoToricVariety(Delta=diamond)
1236
sage: FTV.coordinate_points()
1237
(0, 1, 2, 3)
1238
sage: FTV.gens()
1239
(z0, z1, z2, z3)
1240
sage: FTV_res = FTV.resolve(new_points=[6,8])
1241
Traceback (most recent call last):
1242
...
1243
ValueError: the origin (point #6)
1244
cannot be used for subdivision!
1245
sage: FTV_res = FTV.resolve(new_points=[8,5])
1246
sage: FTV_res
1247
2-d CPR-Fano toric variety covered by 6 affine patches
1248
sage: FTV_res.coordinate_points()
1249
(0, 1, 2, 3, 8, 5)
1250
sage: FTV_res.gens()
1251
(z0, z1, z2, z3, z8, z5)
1252
1253
sage: TV_res = FTV.resolve(new_rays=[(1,2)])
1254
sage: TV_res
1255
2-d toric variety covered by 5 affine patches
1256
sage: TV_res.gens()
1257
(z0, z1, z2, z3, z4)
1258
"""
1259
# Reasons to override the base class:
1260
# - allow using polytope point indices for subdivision
1261
# - handle automatic name creation in a different fashion
1262
# - return CPR-Fano toric variety if the above feature was used and
1263
# just toric variety if subdivision involves rays
1264
if "new_rays" in kwds:
1265
if "new_points" in kwds:
1266
raise ValueError("you cannot give new_points and new_rays at "
1267
"the same time!")
1268
return super(CPRFanoToricVariety_field, self).resolve(**kwds)
1269
# Now we need to construct another Fano variety
1270
new_points = kwds.pop("new_points", ())
1271
coordinate_points = self.coordinate_points()
1272
new_points = tuple(point for point in new_points
1273
if point not in coordinate_points)
1274
Delta_polar = self._Delta_polar
1275
if Delta_polar.origin() in new_points:
1276
raise ValueError("the origin (point #%d) cannot be used for "
1277
"subdivision!" % Delta_polar.origin())
1278
if new_points:
1279
coordinate_points = coordinate_points + new_points
1280
point_to_ray = dict()
1281
for n, point in enumerate(coordinate_points):
1282
point_to_ray[point] = n
1283
else:
1284
point_to_ray = self._point_to_ray
1285
new_rays = [Delta_polar.point(point) for point in new_points]
1286
coordinate_name_indices = kwds.pop("coordinate_name_indices",
1287
coordinate_points)
1288
fan = self.fan()
1289
if "coordinate_names" in kwds:
1290
coordinate_names = kwds.pop("coordinate_names")
1291
else:
1292
coordinate_names = list(self.variable_names())
1293
coordinate_names.extend(normalize_names(ngens=len(new_rays),
1294
indices=coordinate_name_indices[fan.nrays():],
1295
prefix=self._coordinate_prefix))
1296
coordinate_names.append(self._coordinate_prefix + "+")
1297
rfan = fan.subdivide(new_rays=new_rays, **kwds)
1298
resolution = CPRFanoToricVariety_field(Delta_polar, rfan,
1299
coordinate_points, point_to_ray, coordinate_names,
1300
coordinate_name_indices, self.base_ring())
1301
R = self.coordinate_ring()
1302
R_res = resolution.coordinate_ring()
1303
resolution_map = resolution.hom(R.hom(R_res.gens()[:R.ngens()]), self)
1304
resolution._resolution_map = resolution_map
1305
return resolution
1306
1307
1308
class AnticanonicalHypersurface(AlgebraicScheme_subscheme_toric):
1309
r"""
1310
Construct an anticanonical hypersurface of a CPR-Fano toric variety.
1311
1312
INPUT:
1313
1314
- ``P_Delta`` -- :class:`CPR-Fano toric variety
1315
<CPRFanoToricVariety_field>` associated to a reflexive polytope
1316
`\Delta`;
1317
1318
- see :meth:`CPRFanoToricVariety_field.anticanonical_hypersurface` for
1319
documentation on all other acceptable parameters.
1320
1321
OUTPUT:
1322
1323
- :class:`anticanonical hypersurface <AnticanonicalHypersurface>` of
1324
``P_Delta`` (with the extended base field, if necessary).
1325
1326
EXAMPLES::
1327
1328
sage: P1xP1 = CPRFanoToricVariety(
1329
... Delta_polar=lattice_polytope.octahedron(2))
1330
sage: import sage.schemes.toric.fano_variety as ftv
1331
sage: ftv.AnticanonicalHypersurface(P1xP1)
1332
Closed subscheme of 2-d CPR-Fano toric variety
1333
covered by 4 affine patches defined by:
1334
a1*z0^2*z1^2 + a0*z1^2*z2^2 + a6*z0*z1*z2*z3
1335
+ a3*z0^2*z3^2 + a2*z2^2*z3^2
1336
1337
See :meth:`~CPRFanoToricVariety_field.anticanonical_hypersurface()` for a
1338
more elaborate example.
1339
"""
1340
def __init__(self, P_Delta, monomial_points=None, coefficient_names=None,
1341
coefficient_name_indices=None, coefficients=None):
1342
r"""
1343
See :meth:`CPRFanoToricVariety_field.anticanonical_hypersurface` for
1344
documentation.
1345
1346
TESTS::
1347
1348
sage: P1xP1 = CPRFanoToricVariety(
1349
... Delta_polar=lattice_polytope.octahedron(2))
1350
sage: import sage.schemes.toric.fano_variety as ftv
1351
sage: ftv.AnticanonicalHypersurface(P1xP1)
1352
Closed subscheme of 2-d CPR-Fano toric variety
1353
covered by 4 affine patches defined by:
1354
a1*z0^2*z1^2 + a0*z1^2*z2^2 + a6*z0*z1*z2*z3
1355
+ a3*z0^2*z3^2 + a2*z2^2*z3^2
1356
"""
1357
if not is_CPRFanoToricVariety(P_Delta):
1358
raise TypeError("anticanonical hypersurfaces can only be "
1359
"constructed for CPR-Fano toric varieties!"
1360
"\nGot: %s" % P_Delta)
1361
Delta = P_Delta.Delta()
1362
Delta_polar = Delta.polar()
1363
# Monomial points normalization
1364
if monomial_points == "vertices":
1365
monomial_points = range(Delta.nvertices())
1366
elif monomial_points == "all":
1367
monomial_points = range(Delta.npoints())
1368
elif monomial_points == "vertices+origin":
1369
monomial_points = range(Delta.nvertices())
1370
monomial_points.append(Delta.origin())
1371
elif monomial_points == "simplified" or monomial_points is None:
1372
monomial_points = Delta.skeleton_points(Delta.dim() - 2)
1373
monomial_points.append(Delta.origin())
1374
elif isinstance(monomial_points, str):
1375
raise ValueError("%s is an unsupported description of monomial "
1376
"points!" % monomial_points)
1377
monomial_points = tuple(monomial_points)
1378
self._monomial_points = monomial_points
1379
# Make the necessary ambient space
1380
if coefficient_name_indices is None:
1381
coefficient_name_indices = monomial_points
1382
if coefficients is None:
1383
coefficient_names = normalize_names(
1384
coefficient_names, len(monomial_points),
1385
DEFAULT_COEFFICIENT, coefficient_name_indices)
1386
# We probably don't want it: the analog in else-branch is unclear.
1387
# self._coefficient_names = coefficient_names
1388
F = add_variables(P_Delta.base_ring(), coefficient_names)
1389
coefficients = (F(coef) for coef in coefficient_names)
1390
else:
1391
variables = []
1392
for c in coefficients:
1393
variables.extend(map(str, SR(c).variables()))
1394
F = add_variables(P_Delta.base_ring(), variables)
1395
# Direct conversion "a/b" to F does not work in Sage-4.6.alpha3,
1396
# so we go through SR, even though it is quite slow.
1397
coefficients = (F(SR(coef)) for coef in coefficients)
1398
P_Delta = P_Delta.base_extend(F)
1399
# Defining polynomial
1400
h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n)
1401
** (Delta.point(m) * Delta_polar.point(n) + 1)
1402
for n in P_Delta.coordinate_points())
1403
for m, coef in zip(monomial_points, coefficients))
1404
super(AnticanonicalHypersurface, self).__init__(P_Delta, h)
1405
1406
1407
class NefCompleteIntersection(AlgebraicScheme_subscheme_toric):
1408
r"""
1409
Construct a nef complete intersection in a CPR-Fano toric variety.
1410
1411
INPUT:
1412
1413
- ``P_Delta`` -- a :class:`CPR-Fano toric variety
1414
<CPRFanoToricVariety_field>` associated to a reflexive polytope
1415
`\Delta`;
1416
1417
- see :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for
1418
documentation on all other acceptable parameters.
1419
1420
OUTPUT:
1421
1422
- a :class:`nef complete intersection <NefCompleteIntersection>` of
1423
``P_Delta`` (with the extended base field, if necessary).
1424
1425
EXAMPLES::
1426
1427
sage: o = lattice_polytope.octahedron(3)
1428
sage: np = o.nef_partitions()[0]
1429
sage: np
1430
Nef-partition {0, 1, 3} U {2, 4, 5}
1431
sage: X = CPRFanoToricVariety(Delta_polar=o)
1432
sage: X.nef_complete_intersection(np)
1433
Closed subscheme of 3-d CPR-Fano toric variety
1434
covered by 8 affine patches defined by:
1435
a1*z0^2*z1 + a4*z0*z1*z3 + a3*z1*z3^2
1436
+ a0*z0^2*z4 + a5*z0*z3*z4 + a2*z3^2*z4,
1437
b0*z1*z2^2 + b1*z2^2*z4 + b4*z1*z2*z5
1438
+ b5*z2*z4*z5 + b3*z1*z5^2 + b2*z4*z5^2
1439
1440
See :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for a
1441
more elaborate example.
1442
"""
1443
def __init__(self, P_Delta, nef_partition,
1444
monomial_points="all", coefficient_names=None,
1445
coefficient_name_indices=None, coefficients=None):
1446
r"""
1447
See :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for
1448
documentation.
1449
1450
TESTS::
1451
1452
sage: o = lattice_polytope.octahedron(3)
1453
sage: np = o.nef_partitions()[0]
1454
sage: np
1455
Nef-partition {0, 1, 3} U {2, 4, 5}
1456
sage: X = CPRFanoToricVariety(Delta_polar=o)
1457
sage: from sage.schemes.toric.fano_variety import *
1458
sage: NefCompleteIntersection(X, np)
1459
Closed subscheme of 3-d CPR-Fano toric variety
1460
covered by 8 affine patches defined by:
1461
a1*z0^2*z1 + a4*z0*z1*z3 + a3*z1*z3^2
1462
+ a0*z0^2*z4 + a5*z0*z3*z4 + a2*z3^2*z4,
1463
b0*z1*z2^2 + b1*z2^2*z4 + b4*z1*z2*z5
1464
+ b5*z2*z4*z5 + b3*z1*z5^2 + b2*z4*z5^2
1465
"""
1466
if not is_CPRFanoToricVariety(P_Delta):
1467
raise TypeError("nef complete intersections can only be "
1468
"constructed for CPR-Fano toric varieties!"
1469
"\nGot: %s" % P_Delta)
1470
if nef_partition.Delta() is not P_Delta.Delta():
1471
raise ValueError("polytopes 'Delta' of the nef-partition and the "
1472
"CPR-Fano toric variety must be the same!")
1473
self._nef_partition = nef_partition
1474
k = nef_partition.nparts()
1475
# Pre-normalize all parameters
1476
if isinstance(monomial_points, str):
1477
monomial_points = [monomial_points] * k
1478
if coefficient_names is None:
1479
coefficient_names = [None] * k
1480
if coefficient_name_indices is None:
1481
coefficient_name_indices = [None] * k
1482
if coefficients is None:
1483
coefficients = [None] * k
1484
1485
polynomials = []
1486
Delta_polar = P_Delta.Delta_polar()
1487
for i in range(k):
1488
Delta_i = nef_partition.Delta(i)
1489
# Monomial points normalization
1490
if monomial_points[i] == "vertices":
1491
monomial_points[i] = range(Delta_i.nvertices())
1492
elif monomial_points[i] == "all":
1493
monomial_points[i] = range(Delta_i.npoints())
1494
elif monomial_points[i] == "vertices+origin":
1495
monomial_points[i] = range(Delta_i.nvertices())
1496
if (Delta_i.origin() is not None
1497
and Delta_i.origin() >= Delta_i.nvertices()):
1498
monomial_points[i].append(Delta_i.origin())
1499
elif isinstance(monomial_points[i], str):
1500
raise ValueError("'%s' is an unsupported description of "
1501
"monomial points!" % monomial_points[i])
1502
monomial_points[i] = tuple(monomial_points[i])
1503
# Extend the base ring of the ambient space if necessary
1504
if coefficient_name_indices[i] is None:
1505
coefficient_name_indices[i] = monomial_points[i]
1506
if coefficients[i] is None:
1507
coefficient_names[i] = normalize_names(
1508
coefficient_names[i], len(monomial_points[i]),
1509
DEFAULT_COEFFICIENTS[i], coefficient_name_indices[i])
1510
F = add_variables(P_Delta.base_ring(), coefficient_names[i])
1511
coefficients[i] = (F(coef) for coef in coefficient_names[i])
1512
else:
1513
variables = []
1514
for c in coefficients[i]:
1515
variables.extend(map(str, SR(c).variables()))
1516
F = add_variables(P_Delta.base_ring(), variables)
1517
# Direct conversion "a/b" to F does not work in Sage-4.6.alpha3
1518
# so we go through SR, even though it is quite slow.
1519
coefficients[i] = (F(SR(coef)) for coef in coefficients[i])
1520
P_Delta = P_Delta.base_extend(F)
1521
# Defining polynomial
1522
h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n)
1523
** (Delta_i.point(m) * Delta_polar.point(n)
1524
+ (nef_partition.part_of_point(n) == i))
1525
for n in P_Delta.coordinate_points())
1526
for m, coef in zip(monomial_points[i], coefficients[i]))
1527
polynomials.append(h)
1528
self._monomial_points = tuple(monomial_points)
1529
super(NefCompleteIntersection, self).__init__(P_Delta, polynomials)
1530
1531
def nef_partition(self):
1532
r"""
1533
Return the nef-partition associated to ``self``.
1534
1535
OUTPUT:
1536
1537
- a :class:`nef-partition
1538
<sage.geometry.lattice_polytope.NefPartition>`.
1539
1540
EXAMPLES::
1541
1542
sage: o = lattice_polytope.octahedron(3)
1543
sage: np = o.nef_partitions()[0]
1544
sage: np
1545
Nef-partition {0, 1, 3} U {2, 4, 5}
1546
sage: X = CPRFanoToricVariety(Delta_polar=o)
1547
sage: CI = X.nef_complete_intersection(np)
1548
sage: CI
1549
Closed subscheme of 3-d CPR-Fano toric variety
1550
covered by 8 affine patches defined by:
1551
a1*z0^2*z1 + a4*z0*z1*z3 + a3*z1*z3^2
1552
+ a0*z0^2*z4 + a5*z0*z3*z4 + a2*z3^2*z4,
1553
b0*z1*z2^2 + b1*z2^2*z4 + b4*z1*z2*z5
1554
+ b5*z2*z4*z5 + b3*z1*z5^2 + b2*z4*z5^2
1555
sage: CI.nef_partition()
1556
Nef-partition {0, 1, 3} U {2, 4, 5}
1557
sage: CI.nef_partition() is np
1558
True
1559
"""
1560
return self._nef_partition
1561
1562
1563
def add_variables(field, variables):
1564
r"""
1565
Extend ``field`` to include all ``variables``.
1566
1567
INPUT:
1568
1569
- ``field`` - a field;
1570
1571
- ``variables`` - a list of strings.
1572
1573
OUTPUT:
1574
1575
- a fraction field extending the original ``field``, which has all
1576
``variables`` among its generators.
1577
1578
EXAMPLES:
1579
1580
We start with the rational field and slowly add more variables::
1581
1582
sage: from sage.schemes.toric.fano_variety import *
1583
sage: F = add_variables(QQ, []); F # No extension
1584
Rational Field
1585
sage: F = add_variables(QQ, ["a"]); F
1586
Fraction Field of Univariate Polynomial Ring
1587
in a over Rational Field
1588
sage: F = add_variables(F, ["a"]); F
1589
Fraction Field of Univariate Polynomial Ring
1590
in a over Rational Field
1591
sage: F = add_variables(F, ["b", "c"]); F
1592
Fraction Field of Multivariate Polynomial Ring
1593
in a, b, c over Rational Field
1594
sage: F = add_variables(F, ["c", "d", "b", "c", "d"]); F
1595
Fraction Field of Multivariate Polynomial Ring
1596
in a, b, c, d over Rational Field
1597
"""
1598
if not variables:
1599
return field
1600
if is_FractionField(field):
1601
# Q(a) ---> Q(a, b) rather than Q(a)(b)
1602
R = field.ring()
1603
if is_PolynomialRing(R) or is_MPolynomialRing(R):
1604
new_variables = list(R.variable_names())
1605
for v in variables:
1606
if v not in new_variables:
1607
new_variables.append(v)
1608
if len(new_variables) > R.ngens():
1609
return PolynomialRing(R.base_ring(),
1610
new_variables).fraction_field()
1611
else:
1612
return field
1613
# "Intelligent extension" didn't work, use the "usual one."
1614
new_variables = []
1615
for v in variables:
1616
if v not in new_variables:
1617
new_variables.append(v)
1618
return PolynomialRing(field, new_variables).fraction_field()
1619
1620
1621