Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/toric/points.py
8820 views
1
# -*- coding: utf-8 -*-
2
"""
3
Enumerate Points of a Toric Variety
4
5
The classes here are not meant to be instatiated manually. Instead,
6
you should always use the methods of the :class:`point set
7
<sage.schemes.toric.homset.SchemeHomset_points_toric_field>` of the
8
variety.
9
10
In this module, points are always represented by tuples instead of
11
Sage's class for points of the toric variety. All Sage library code
12
must then convert it to proper point objects before returning it to
13
the user.
14
15
EXAMPLES::
16
17
sage: P2 = toric_varieties.P2(base_ring=GF(3))
18
sage: point_set = P2.point_set()
19
sage: point_set.cardinality()
20
13
21
sage: iter(point_set).next()
22
[0 : 0 : 1]
23
sage: list(point_set)[0:5]
24
[[0 : 0 : 1], [1 : 0 : 0], [0 : 1 : 0], [0 : 1 : 1], [0 : 1 : 2]]
25
"""
26
27
#*****************************************************************************
28
# Copyright (C) 2013 Volker Braun <[email protected]>
29
#
30
# Distributed under the terms of the GNU General Public License (GPL)
31
# as published by the Free Software Foundation; either version 3 of
32
# the License, or (at your option) any later version.
33
# http://www.gnu.org/licenses/
34
#*****************************************************************************
35
36
37
38
from copy import copy
39
40
from sage.combinat.cartesian_product import CartesianProduct
41
from sage.misc.misc import powerset, prod
42
from sage.misc.cachefunc import cached_method
43
44
45
class InfinitePointEnumerator(object):
46
47
def __init__(self, fan, ring):
48
"""
49
Point enumerator for infinite fields.
50
51
INPUT:
52
53
- ``fan`` -- fan of the toric variety.
54
55
- ``ring`` -- infinite base ring over which to enumerate
56
points.
57
58
TESTS::
59
60
sage: from sage.schemes.toric.points import InfinitePointEnumerator
61
sage: fan = toric_varieties.P2().fan()
62
sage: n = InfinitePointEnumerator(fan, QQ)
63
sage: ni = iter(n)
64
sage: [ni.next() for k in range(10)]
65
[(0, 1, 1), (1, 1, 1), (-1, 1, 1), (1/2, 1, 1), (-1/2, 1, 1),
66
(2, 1, 1), (-2, 1, 1), (1/3, 1, 1), (-1/3, 1, 1), (3, 1, 1)]
67
68
sage: X = ToricVariety(Fan([], lattice=ZZ^0))
69
sage: X.point_set().cardinality()
70
1
71
sage: X.base_ring().is_finite()
72
False
73
sage: X.point_set().list()
74
([],)
75
"""
76
self.ring = ring
77
self.fan = fan
78
79
def __iter__(self):
80
"""
81
Iterate over the points.
82
83
OUTPUT:
84
85
Iterator over points.
86
87
EXAMPLES::
88
89
sage: from sage.schemes.toric.points import InfinitePointEnumerator
90
sage: fan = toric_varieties.P2().fan()
91
sage: n = InfinitePointEnumerator(fan, QQ)
92
sage: ni = iter(n)
93
sage: [ni.next() for k in range(5)]
94
[(0, 1, 1), (1, 1, 1), (-1, 1, 1), (1/2, 1, 1), (-1/2, 1, 1)]
95
"""
96
rays = self.fan().rays() + self.fan().virtual_rays()
97
n = len(rays)
98
if n == 0:
99
yield tuple()
100
else:
101
R = self.ring
102
p = [R.one() for k in range(n)]
103
for r in R:
104
p[0] = r
105
yield tuple(p)
106
107
108
class NaiveFinitePointEnumerator(object):
109
110
def __init__(self, fan, ring):
111
"""
112
The naive point enumerator.
113
114
This is very slow.
115
116
INPUT:
117
118
- ``fan`` -- fan of the toric variety.
119
120
- ``ring`` -- finite base ring over which to enumerate points.
121
122
EXAMPLES::
123
124
sage: from sage.schemes.toric.points import NaiveFinitePointEnumerator
125
sage: fan = toric_varieties.P2().fan()
126
sage: n = NaiveFinitePointEnumerator(fan, GF(3))
127
sage: iter(n).next()
128
(0, 0, 1)
129
"""
130
assert ring.is_finite()
131
self.ring = ring
132
self.fan = fan
133
134
@cached_method
135
def units(self):
136
"""
137
Return the units in the base field.
138
139
EXAMPLES::
140
141
sage: ne = toric_varieties.P2(base_ring=GF(5)).point_set()._naive_enumerator()
142
sage: ne.units()
143
(1, 2, 3, 4)
144
"""
145
return tuple(x for x in self.ring if x != 0)
146
147
@cached_method
148
def roots(self, n):
149
"""
150
Return the n-th roots in the base field
151
152
EXAMPLES::
153
154
sage: ne = toric_varieties.P2(base_ring=GF(5)).point_set()._naive_enumerator()
155
sage: ne.roots(2)
156
(1, 4)
157
sage: ne.roots(3)
158
(1,)
159
sage: ne.roots(4)
160
(1, 2, 3, 4)
161
"""
162
return tuple(x for x in self.ring if x**n == self.ring.one())
163
164
def _Chow_group_free(self):
165
r"""
166
Return the relations coming from the free part of the Chow group
167
168
OUTPUT:
169
170
A tuple containing the elements of $Hom(A_{d-1,\text{free}},
171
F^\times)$, including the identity.
172
173
EXAMPLES::
174
175
sage: fan = NormalFan(ReflexivePolytope(2, 0))
176
sage: X = ToricVariety(fan, base_field=GF(7))
177
sage: X.Chow_group().degree(1)
178
C3 x Z
179
sage: enum = X.point_set()._naive_enumerator()
180
sage: enum._Chow_group_free()
181
((1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6))
182
"""
183
units = self.units()
184
result = []
185
rays = self.fan().rays() + self.fan().virtual_rays()
186
ker = rays.matrix().integer_kernel().matrix()
187
for phases in CartesianProduct(*([units] * ker.nrows())):
188
phases = tuple(prod(mu**exponent for mu, exponent in zip(phases, column))
189
for column in ker.columns())
190
result.append(phases)
191
return tuple(sorted(result))
192
193
def _Chow_group_torsion(self):
194
r"""
195
Return the relations coming from the torison part of the Chow group
196
197
OUTPUT:
198
199
A tuple containing the non-identity elements of
200
$Hom(A_{d-1,\text{tors}}, F^\times)$
201
202
EXAMPLES::
203
204
sage: fan = NormalFan(ReflexivePolytope(2, 0))
205
sage: X = ToricVariety(fan, base_field=GF(7))
206
sage: X.Chow_group().degree(1)
207
C3 x Z
208
sage: enum = X.point_set()._naive_enumerator()
209
sage: enum._Chow_group_torsion()
210
((1, 2, 4), (1, 4, 2))
211
"""
212
if self.fan.is_smooth():
213
return tuple()
214
rays = self.fan().rays() + self.fan().virtual_rays()
215
image = rays.column_matrix().image()
216
torsion = image.saturation().quotient(image)
217
result = set()
218
for t in torsion:
219
t_lift = t.lift()
220
for root in self.roots(t.order()):
221
phases = tuple(root**exponent for exponent in t_lift)
222
result.add(phases)
223
result.remove(tuple(self.ring.one() for r in rays))
224
return tuple(sorted(result))
225
226
@cached_method
227
def rescalings(self):
228
"""
229
Return the rescalings of homogeneous coordinates.
230
231
OUTPUT:
232
233
A tuple containing all points that are equivalent to
234
`[1:1:\dots:1]`, the distinguished point of the big torus
235
orbit.
236
237
EXAMPLES::
238
239
sage: ni = toric_varieties.P2_123(base_ring=GF(5)).point_set()._naive_enumerator()
240
sage: ni.rescalings()
241
((1, 1, 1), (1, 4, 4), (4, 2, 3), (4, 3, 2))
242
243
sage: ni = toric_varieties.dP8(base_ring=GF(3)).point_set()._naive_enumerator()
244
sage: ni.rescalings()
245
((1, 1, 1, 1), (1, 2, 2, 2), (2, 1, 2, 1), (2, 2, 1, 2))
246
247
sage: ni = toric_varieties.P1xP1(base_ring=GF(3)).point_set()._naive_enumerator()
248
sage: ni.rescalings()
249
((1, 1, 1, 1), (1, 1, 2, 2), (2, 2, 1, 1), (2, 2, 2, 2))
250
"""
251
free = self._Chow_group_free()
252
tors = self._Chow_group_torsion()
253
if len(tors) == 0: # optimization for smooth fans
254
return free
255
result = set(free)
256
for f, t in CartesianProduct(free, tors):
257
phases = tuple(x*y for x, y in zip(f, t))
258
result.add(phases)
259
return tuple(sorted(result))
260
261
def orbit(self, point):
262
"""
263
Return the orbit of homogeneous coordinates under rescalings.
264
265
OUTPUT:
266
267
The set of all homogeneous coordinates that are equivalent to ``point``.
268
269
EXAMPLES::
270
271
sage: ne = toric_varieties.P2_123(base_ring=GF(7)).point_set()._naive_enumerator()
272
sage: sorted(ne.orbit([1, 0, 0]))
273
[(1, 0, 0), (2, 0, 0), (4, 0, 0)]
274
sage: sorted(ne.orbit([0, 1, 0]))
275
[(0, 1, 0), (0, 6, 0)]
276
sage: sorted(ne.orbit([0, 0, 1]))
277
[(0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 0, 5), (0, 0, 6)]
278
sage: sorted(ne.orbit([1, 1, 0]))
279
[(1, 1, 0), (1, 6, 0), (2, 1, 0), (2, 6, 0), (4, 1, 0), (4, 6, 0)]
280
"""
281
result = set()
282
for phases in self.rescalings():
283
p = tuple(mu*z for mu, z in zip(point, phases))
284
result.add(p)
285
return frozenset(result)
286
287
def cone_iter(self):
288
"""
289
Iterate over all cones of the fan
290
291
OUTPUT:
292
293
Iterator over the cones, starting with the high-dimensional
294
ones.
295
296
EXAMPLES::
297
298
sage: ne = toric_varieties.dP6(base_ring=GF(11)).point_set()._naive_enumerator()
299
sage: for cone in ne.cone_iter():
300
....: print cone.ambient_ray_indices()
301
(0, 1)
302
(1, 2)
303
(2, 3)
304
(3, 4)
305
(4, 5)
306
(0, 5)
307
(0,)
308
(1,)
309
(2,)
310
(3,)
311
(4,)
312
(5,)
313
()
314
"""
315
fan = self.fan
316
for d in range(fan.dim(), -1, -1):
317
for cone in fan.cones(d):
318
yield cone
319
320
def coordinate_iter(self):
321
"""
322
Iterate over all distinct homogeneous coordinates.
323
324
This method does NOT identify homogeneous coordinates that are
325
equivalent by a homogeneous rescaling.
326
327
OUTPUT:
328
329
An iterator over the points.
330
331
EXAMPLES::
332
333
sage: F2 = GF(2)
334
sage: ni = toric_varieties.P2(base_ring=F2).point_set()._naive_enumerator()
335
sage: list(ni.coordinate_iter())
336
[(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
337
338
sage: ni = toric_varieties.P1xP1(base_ring=F2).point_set()._naive_enumerator()
339
sage: list(ni.coordinate_iter())
340
[(0, 1, 0, 1), (1, 0, 0, 1), (1, 0, 1, 0),
341
(0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 1, 1),
342
(1, 1, 0, 1), (1, 1, 1, 0), (1, 1, 1, 1)]
343
344
TESTS::
345
346
sage: V = ToricVariety(Fan([Cone([(1,1)])]), base_ring=GF(3))
347
sage: ni = V.point_set()._naive_enumerator()
348
sage: list(ni.coordinate_iter())
349
[(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (2, 2)]
350
"""
351
units = [x for x in self.ring if x != 0]
352
zero = self.ring.zero()
353
rays = self.fan.rays() + self.fan.virtual_rays()
354
big_torus = [units] * len(rays)
355
for cone in self.cone_iter():
356
patch = copy(big_torus)
357
for i in cone.ambient_ray_indices():
358
patch[i] = [zero]
359
for p in CartesianProduct(*patch):
360
yield tuple(p)
361
362
def __iter__(self):
363
"""
364
Iterate over the distinct points of the toric variety.
365
366
This function does identify orbits under the homogeneous
367
rescalings, and returns precisely one representative per
368
orbit.
369
370
OUTPUT:
371
372
Iterator over points.
373
374
EXAMPLES:
375
376
sage: ni = toric_varieties.P2(base_ring=GF(2)).point_set()._naive_enumerator()
377
sage: list(ni)
378
[(0, 0, 1), (1, 0, 0), (0, 1, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
379
380
sage: ni = toric_varieties.P1xP1(base_ring=GF(3)).point_set()._naive_enumerator()
381
sage: list(ni)
382
[(0, 1, 0, 1), (1, 0, 0, 1), (1, 0, 1, 0), (0, 1, 1, 0),
383
(0, 1, 1, 1), (0, 1, 1, 2), (1, 0, 1, 1), (1, 0, 1, 2),
384
(1, 1, 0, 1), (1, 2, 0, 1), (1, 1, 1, 0), (1, 2, 1, 0),
385
(1, 1, 1, 1), (1, 1, 1, 2), (1, 2, 1, 1), (1, 2, 1, 2)]
386
"""
387
seen = set()
388
for p in self.coordinate_iter():
389
if p in seen:
390
continue
391
seen.update(self.orbit(p))
392
yield p
393
394
395