Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/geometry/toric_lattice_element.pyx
4096 views
1
r"""
2
Toric lattice elements
3
4
This module was designed as a part of the framework for toric varieties
5
(:mod:`~sage.schemes.toric.variety`,
6
:mod:`~sage.schemes.toric.fano_variety`).
7
8
AUTHORS:
9
10
- Andrey Novoseltsev (2010-05-27): initial version.
11
12
TESTS:
13
14
Let's create some lattices first::
15
16
sage: N = ToricLattice(3)
17
sage: M = N.dual()
18
19
Now we are ready to create elements of toric lattices::
20
21
sage: n = N([1,2,3])
22
sage: n
23
N(1, 2, 3)
24
sage: m = M(1,2,3)
25
sage: m
26
M(1, 2, 3)
27
28
Dual lattices can act on each other::
29
30
sage: n * m
31
14
32
sage: m * n
33
14
34
35
You can also add elements of the same lattice or scale them::
36
37
sage: 2 * n
38
N(2, 4, 6)
39
sage: n * 2
40
N(2, 4, 6)
41
sage: n + n
42
N(2, 4, 6)
43
44
However, you cannot "mix wrong lattices" in your expressions::
45
46
sage: n + m
47
Traceback (most recent call last):
48
...
49
TypeError: unsupported operand parent(s) for '+':
50
'3-d lattice N' and '3-d lattice M'
51
sage: n * n
52
Traceback (most recent call last):
53
...
54
TypeError: elements of the same toric lattice cannot be multiplied!
55
sage: n == m
56
False
57
58
Note that ``n`` and ``m`` are not equal to each other even though they are
59
both "just (1,2,3)." Moreover, you cannot easily convert elements between
60
toric lattices::
61
62
sage: M(n)
63
Traceback (most recent call last):
64
...
65
TypeError: N(1, 2, 3) cannot be converted to 3-d lattice M!
66
67
If you really need to consider elements of one lattice as elements of another,
68
you can either use intermediate conversion to "just a vector"::
69
70
sage: ZZ3 = ZZ^3
71
sage: n_in_M = M(ZZ3(n))
72
sage: n_in_M
73
M(1, 2, 3)
74
sage: n == n_in_M
75
False
76
sage: n_in_M == m
77
True
78
79
Or you can create a homomorphism from one lattice to any other::
80
81
sage: h = N.hom(identity_matrix(3), M)
82
sage: h(n)
83
M(1, 2, 3)
84
"""
85
# The "tutorial" above is a truncated version of one in toric_lattice.py.
86
87
88
#*****************************************************************************
89
# Copyright (C) 2010 Andrey Novoseltsev <[email protected]>
90
# Copyright (C) 2010 William Stein <[email protected]>
91
#
92
# Distributed under the terms of the GNU General Public License (GPL)
93
#
94
# http://www.gnu.org/licenses/
95
#*****************************************************************************
96
97
98
include '../ext/cdefs.pxi'
99
include '../ext/stdsage.pxi' # Needed for PY_NEW
100
101
from sage.geometry.toric_plotter import ToricPlotter
102
from sage.modules.vector_integer_dense cimport Vector_integer_dense
103
from sage.structure.coerce_exceptions import CoercionException
104
from sage.structure.element cimport Element, Vector
105
from sage.rings.integer cimport Integer
106
107
108
def is_ToricLatticeElement(x):
109
r"""
110
Check if ``x`` is an element of a toric lattice.
111
112
INPUT:
113
114
- ``x`` -- anything.
115
116
OUTPUT:
117
118
- ``True`` if ``x`` is an element of a toric lattice, ``False`` otherwise.
119
120
EXAMPLES::
121
122
sage: from sage.geometry.toric_lattice_element import (
123
... is_ToricLatticeElement)
124
sage: is_ToricLatticeElement(1)
125
False
126
sage: e = ToricLattice(3).an_element()
127
sage: e
128
N(1, 0, 0)
129
sage: is_ToricLatticeElement(e)
130
True
131
"""
132
return isinstance(x, ToricLatticeElement)
133
134
135
# Why do we need a special class:
136
# - customize output to include lattice name
137
# - prohibit operations mixing "wrong" lattices
138
cdef class ToricLatticeElement(Vector_integer_dense):
139
r"""
140
Create an element of a toric lattice.
141
142
.. WARNING::
143
144
You probably should not construct such elements explicitly.
145
146
INPUT:
147
148
- same as for
149
:class:`~sage.modules.vector_integer_dense.Vector_integer_dense`.
150
151
OUTPUT:
152
153
- element of a toric lattice.
154
155
TESTS::
156
157
sage: N = ToricLattice(3)
158
sage: from sage.geometry.toric_lattice_element import (
159
... ToricLatticeElement)
160
sage: e = ToricLatticeElement(N, [1,2,3])
161
sage: e
162
N(1, 2, 3)
163
sage: TestSuite(e).run()
164
"""
165
166
# We do not add any new functionality, we actually limit the existing one
167
# instead. In particular, there is no need in __init__, but the following
168
# function ensures that _add_ etc. return ToricLatticeElement, rather
169
# than Vector_integer_dense. Its code is copied from the base class with
170
# the type name replacements.
171
# It is not detected by doctest coverage, the original has no
172
# documentation, and I don't feel I can clearly define the exact part of
173
# the initialization process which is done by it. So I will leave it
174
# without any further documentation as well...
175
cdef _new_c(self):
176
cdef ToricLatticeElement y
177
y = PY_NEW(ToricLatticeElement)
178
y._init(self._degree, self._parent)
179
return y
180
181
def __cmp__(self, right):
182
r"""
183
Compare ``self`` and ``right``.
184
185
INPUT:
186
187
- ``right`` -- anything.
188
189
OUTPUT:
190
191
- 0 if ``right`` is an equal element of the same toric lattice as
192
``self``, 1 or -1 otherwise.
193
194
TESTS::
195
196
sage: N = ToricLattice(3)
197
sage: M = N.dual()
198
sage: n = N(1,2,3)
199
sage: m = M(1,2,3)
200
sage: cmp(n, m)
201
1
202
sage: n2 = N(1,2,3)
203
sage: cmp(n, n2)
204
0
205
sage: n is n2
206
False
207
sage: n == 1
208
False
209
"""
210
c = cmp(type(self), type(right))
211
PL = self.parent()
212
PR = right.parent()
213
try:
214
c = cmp(PL.ambient_module(), PR.ambient_module())
215
if c:
216
return c
217
except AttributeError:
218
return cmp(PL, PR)
219
# Now use the real comparison of vectors
220
return self._cmp_c_impl(right)
221
222
# For some reason, vectors work just fine without redefining this function
223
# from the base class, but if it is not here, we get "unhashable type"...
224
def __hash__(self):
225
r"""
226
Return the hash of ``self``.
227
228
OUTPUT:
229
230
- integer.
231
232
TESTS::
233
234
sage: N = ToricLattice(3)
235
sage: n = N(1,2,3)
236
sage: hash(n)
237
Traceback (most recent call last):
238
...
239
TypeError: mutable vectors are unhashable
240
sage: n.set_immutable()
241
sage: hash(n) == hash(n)
242
True
243
"""
244
return Vector_integer_dense.__hash__(self)
245
246
cpdef _act_on_(self, other, bint self_on_left):
247
"""
248
Act on ``other``.
249
250
INPUT:
251
252
- ``other`` - :class:`ToricLatticeElement`.
253
254
OUTPUT:
255
256
- integer, if ``other`` is an element of the dual lattice of ``self``;
257
258
- ``CoercionException`` is raised if ``other`` is an element of
259
an incompatible toric lattice;
260
261
- standard output for ``self`` acting as an integral vector on
262
``other`` if the latter one is not an element of a toric lattice.
263
264
TESTS::
265
266
sage: N = ToricLattice(3)
267
sage: M = N.dual()
268
sage: n = N(1,2,3)
269
sage: m = M(1,2,3)
270
sage: n * m # indirect doctest
271
14
272
273
Now we test behaviour with other types::
274
275
sage: v = vector([1, 2, 3])
276
sage: v * n == n * v
277
True
278
sage: v = vector([1, 1/2, 3/4])
279
sage: v * n == n * v
280
True
281
sage: A = matrix(3, range(9))
282
sage: A * n
283
(8, 26, 44)
284
sage: n * A
285
(24, 30, 36)
286
sage: B = A / 3
287
sage: B * n
288
(8/3, 26/3, 44/3)
289
sage: n * B
290
(8, 10, 12)
291
"""
292
Ns = self.parent()
293
# We try to deal only with the case of two lattice elements...
294
if is_ToricLatticeElement(other):
295
if other.parent().ambient_module() is Ns.ambient_module().dual():
296
# Our own _dot_product_ is disabled
297
return Vector_integer_dense._dot_product_(self, other)
298
raise CoercionException("only elements of dual toric lattices "
299
"can act on each other!")
300
# ... however we also need to treat the case when other is an integral
301
# vector, since otherwise it will be coerced to the parent of self and
302
# then the dot product will be called for elements of the same lattice
303
if isinstance(other, Vector_integer_dense):
304
return Vector_integer_dense._dot_product_(self, other)
305
# We also allow action on elements of lattice quotients
306
try:
307
lift = other.lift()
308
if is_ToricLatticeElement(lift):
309
if other.parent().W().is_submodule(Ns.dual().W()):
310
return Vector_integer_dense._dot_product_(self, lift)
311
raise CoercionException("only elements of dual toric lattices "
312
"can act on each other!")
313
except AttributeError: # No lift
314
pass
315
# Now let the standard framework work...
316
return Vector_integer_dense._act_on_(self, other, self_on_left)
317
318
# We need to override this function to prohibit default behaviour.
319
# It seems to be called when right is in the same lattice as self, which
320
# is wrong from our point of view.
321
cpdef Element _dot_product_(self, Vector right):
322
"""
323
Raise a ``TypeError`` exception.
324
325
Dot product is not defined on toric lattices (there are actions of
326
dual lattices on each other instead).
327
328
INPUT:
329
330
- ``right`` - vector.
331
332
OUTPUT:
333
334
- ``TypeError`` exception is raised.
335
336
TESTS::
337
338
sage: N = ToricLattice(3)
339
sage: M = N.dual()
340
sage: n = N(1,2,3)
341
sage: m = M(1,2,3)
342
sage: n * n # indirect doctest
343
Traceback (most recent call last):
344
...
345
TypeError: elements of the same
346
toric lattice cannot be multiplied!
347
"""
348
raise TypeError("elements of the same toric lattice cannot be "
349
"multiplied!")
350
351
def _latex_(self):
352
r"""
353
Return a LaTeX representation of ``self``.
354
355
OUTPUT:
356
357
- string.
358
359
TESTS::
360
361
sage: Ld = ToricLattice(3, "L").dual()
362
sage: e = Ld(1,2,3)
363
sage: e._latex_()
364
'\\left(1,\\,2,\\,3\\right)_{L^*}'
365
"""
366
return "%s_{%s}" % (super(ToricLatticeElement, self)._latex_(),
367
self.parent().ambient_module()._latex_name)
368
369
def _repr_(self):
370
r"""
371
Return a string representation of ``self``.
372
373
OUTPUT:
374
375
- string.
376
377
TESTS::
378
379
sage: Ld = ToricLattice(3, "L").dual()
380
sage: e = Ld(1,2,3)
381
sage: e._repr_()
382
'L*(1, 2, 3)'
383
"""
384
return (self.parent().ambient_module()._name
385
+ super(ToricLatticeElement, self)._repr_())
386
387
def __reduce__(self):
388
"""
389
Override the base ``__reduce__`` to correctly pickle/unpickle elements.
390
391
EXAMPLES::
392
393
sage: N = ToricLattice(3)
394
sage: loads(dumps(N(1,2,3)))
395
N(1, 2, 3)
396
"""
397
return (unpickle_v1, (self._parent, self.list(), self._degree, self._is_mutable))
398
399
def plot(self, **options):
400
r"""
401
Plot ``self``.
402
403
INPUT:
404
405
- any options for toric plots (see :func:`toric_plotter.options
406
<sage.geometry.toric_plotter.options>`), none are mandatory.
407
408
OUTPUT:
409
410
- a plot.
411
412
EXAMPLES::
413
414
sage: N = ToricLattice(3)
415
sage: n = N(1,2,3)
416
sage: n.plot()
417
"""
418
tp = ToricPlotter(options, self.parent().degree())
419
tp.adjust_options()
420
return tp.plot_points([self])
421
422
423
def unpickle_v1(parent, entries, degree, is_mutable):
424
"""
425
Unpickle a :class:`ToricLatticeElement`
426
427
INPUT:
428
429
- ``parent`` -- The parent toric lattice.
430
431
- ``entries`` -- a list. The coordinates of the lattice point.
432
433
- ``degree`` -- integer. the dimension of the toric lattice.
434
435
- ``is_mutable`` -- boolean. Whether the lattice element is
436
mutable.
437
438
OUTPUT:
439
440
The :class:`ToricLatticeElement` determined by the input data.
441
442
EXAMPLES::
443
444
sage: N = ToricLattice(3, "lattice")
445
sage: loads(dumps(N(1,2,3))) # indirect test
446
lattice(1, 2, 3)
447
sage: from sage.geometry.toric_lattice_element import unpickle_v1
448
sage: unpickle_v1(N,[1,2,3],3,True)
449
lattice(1, 2, 3)
450
"""
451
cdef ToricLatticeElement v
452
v = PY_NEW(ToricLatticeElement)
453
v._init(degree, parent)
454
cdef Integer z
455
for i from 0 <= i < degree:
456
z = Integer(entries[i])
457
mpz_init_set(v._entries[i], z.value)
458
v._is_mutable = is_mutable
459
return v
460
461