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