Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/geometry/point_collection.pyx
4058 views
1
r"""
2
Point collections
3
4
This module was designed as a part of framework for toric varieties
5
(:mod:`~sage.schemes.toric.variety`,
6
:mod:`~sage.schemes.toric.fano_variety`).
7
8
AUTHORS:
9
10
- Andrey Novoseltsev (2011-04-25): initial version, based on cone module.
11
12
EXAMPLES:
13
14
The idea behind :class:`point collections <PointCollection>` is to have a
15
container for points of the same space that
16
17
* behaves like a tuple *without significant performance penalty*::
18
19
sage: from sage.geometry.point_collection import PointCollection
20
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
21
sage: c = PointCollection(c.rays(), c.lattice())
22
sage: c[1]
23
N(1, 0, 1)
24
sage: for point in c: point
25
N(0, 0, 1)
26
N(1, 0, 1)
27
N(0, 1, 1)
28
N(1, 1, 1)
29
30
* prints like a matrix with points represented by columns and with some
31
indication of the ambient space::
32
33
sage: c
34
[0 1 0 1]
35
[0 0 1 1]
36
[1 1 1 1]
37
in 3-d lattice N
38
39
* allows (cached) access to alternative representations::
40
41
sage: c.set()
42
frozenset([N(0, 1, 1), N(1, 1, 1), N(0, 0, 1), N(1, 0, 1)])
43
44
* allows introduction of additional methods::
45
46
sage: c.basis()
47
[0 1 0]
48
[0 0 1]
49
[1 1 1]
50
in 3-d lattice N
51
52
Examples of natural point collections include ray and line generators of cones,
53
vertices and points of polytopes, normals to facets, their subcollections, etc.
54
55
Using this class for all of the above cases allows for unified interface *and*
56
cache sharing. Suppose that `\Delta` is a reflexive polytope. Then the same
57
point collection can be linked as
58
59
#. vertices of `\Delta`;
60
#. facet normals of its polar `\Delta^\circ`;
61
#. ray generators of the face fan of `\Delta`;
62
#. ray generators of the normal fan of `\Delta`.
63
64
If all these objects are in use and, say, a matrix representation was computed
65
for one of them, it becomes available to all others as well, eliminating the
66
need to spend time and memory four times.
67
"""
68
69
#*****************************************************************************
70
# Copyright (C) 2011 Andrey Novoseltsev <[email protected]>
71
#
72
# Distributed under the terms of the GNU General Public License (GPL)
73
# as published by the Free Software Foundation; either version 2 of
74
# the License, or (at your option) any later version.
75
# http://www.gnu.org/licenses/
76
#*****************************************************************************
77
78
from sage.structure.sage_object cimport SageObject
79
80
from sage.matrix.all import column_matrix
81
from sage.misc.all import latex
82
83
84
def is_PointCollection(x):
85
r"""
86
Check if ``x`` is a :class:`point collection <PointCollection>`.
87
88
INPUT:
89
90
- ``x`` -- anything.
91
92
OUTPUT:
93
94
- ``True`` if ``x`` is a point collection and ``False`` otherwise.
95
96
EXAMPLES::
97
98
sage: from sage.geometry.point_collection import is_PointCollection
99
sage: is_PointCollection(1)
100
False
101
sage: from sage.geometry.point_collection import PointCollection
102
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
103
sage: is_PointCollection(c.rays()) # TODO: make it True
104
False
105
sage: c = PointCollection(c.rays(), c.lattice())
106
sage: is_PointCollection(c)
107
True
108
"""
109
return isinstance(x, PointCollection)
110
111
112
cdef class PointCollection(SageObject):
113
r"""
114
Create a point collection.
115
116
.. WARNING::
117
118
No correctness check or normalization is performed on the input data.
119
This class is designed for internal operations and you probably should
120
not use it directly.
121
122
Point collections are immutable, but cache most of the returned values.
123
124
INPUT:
125
126
- ``points`` -- an iterable structure of immutable elements of ``module``,
127
if ``points`` are already accessible to you as a :class:`tuple`, it is
128
preferable to use it for speed and memory consumption reasons;
129
130
- ``module`` -- an ambient module for ``points``. If ``None``, it will be
131
determined as :func:`parent` of the first point. Of course, this cannot
132
be done if there are no points, so in this case you must give an
133
appropriate ``module`` directly. Note that ``None`` is *not* the default
134
value - you always *must* give this argument explicitly, even if it is
135
``None``.
136
137
OUTPUT:
138
139
- a point collection.
140
"""
141
142
cdef:
143
tuple _points
144
object _module
145
# cache attributes
146
PointCollection _basis
147
object _matrix
148
frozenset _set
149
150
def __init__(self, points, module=None):
151
r"""
152
See :class:`PointCollection` for documentation.
153
154
TESTS::
155
156
sage: from sage.geometry.point_collection import PointCollection
157
sage: v = vector([1,0])
158
sage: v.set_immutable()
159
sage: c = PointCollection([v], ZZ^2)
160
sage: c.module()
161
Ambient free module of rank 2
162
over the principal ideal domain Integer Ring
163
sage: c = PointCollection([v], None)
164
sage: c.module() # Determined automatically
165
Ambient free module of rank 2
166
over the principal ideal domain Integer Ring
167
sage: TestSuite(c).run()
168
"""
169
super(PointCollection, self).__init__()
170
self._points = tuple(points)
171
self._module = self._points[0].parent() if module is None else module
172
173
def __call__(self, *args):
174
r"""
175
Return a subcollection of ``self``.
176
177
INPUT:
178
179
- a list of integers (as a single or many arguments).
180
181
OUTPUT:
182
183
- a :class:`point collection <PointCollection>`.
184
185
TESTS::
186
187
sage: from sage.geometry.point_collection import PointCollection
188
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
189
sage: c = PointCollection(c.rays(), c.lattice())
190
sage: c()
191
[]
192
in 3-d lattice N
193
sage: c(2,1)
194
[0 1]
195
[1 0]
196
[1 1]
197
in 3-d lattice N
198
sage: c(range(4)) == c
199
True
200
"""
201
if len(args) == 1:
202
try:
203
args = tuple(args[0])
204
except TypeError:
205
pass
206
# Avoid creating a copy of self
207
if len(args) == len(self) and args == tuple(range(len(self))):
208
return self
209
else:
210
return PointCollection([self[i] for i in args], self._module)
211
212
def __cmp__(self, right):
213
r"""
214
Compare ``self`` and ``right``.
215
216
INPUT:
217
218
- ``right`` -- anything.
219
220
OUTPUT:
221
222
- 0 if ``right`` is of the same type as ``self`` (i.e. it is another
223
:class:`point collection <PointCollection>`), they have the same
224
:meth:`module`, and their points are the same and listed in the same
225
order. 1 or -1 otherwise.
226
227
TESTS::
228
229
sage: from sage.geometry.point_collection import PointCollection
230
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
231
sage: c = PointCollection(c.rays(), c.lattice())
232
sage: cmp(c, c)
233
0
234
sage: cmp(c, 1) * cmp(1, c)
235
-1
236
"""
237
c = cmp(type(self), type(right))
238
if c != 0:
239
return c
240
cdef PointCollection pc = right
241
c = cmp(self._module, pc._module)
242
if c != 0:
243
return c
244
return cmp(self._points, pc._points)
245
246
def __getitem__(self, n):
247
r"""
248
Return the ``n``-th point of ``self``.
249
250
INPUT:
251
252
- ``n`` -- an integer.
253
254
OUTPUT:
255
256
- a point, an element of the ambient :meth:`module` of ``self``.
257
258
EXAMPLES::
259
260
sage: from sage.geometry.point_collection import PointCollection
261
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
262
sage: c = PointCollection(c.rays(), c.lattice())
263
sage: c[0]
264
N(0, 0, 1)
265
"""
266
return self._points[n]
267
268
def __hash__(self):
269
r"""
270
Return the hash of ``self``.
271
272
OUTPUT:
273
274
- an integer.
275
276
TESTS::
277
278
sage: from sage.geometry.point_collection import PointCollection
279
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
280
sage: c = PointCollection(c.rays(), c.lattice())
281
sage: hash(c) == hash(c)
282
True
283
"""
284
return hash(self._points)
285
286
def __iter__(self):
287
r"""
288
Return an iterator over points of ``self``.
289
290
OUTPUT:
291
292
- an iterator.
293
294
TESTS::
295
296
sage: from sage.geometry.point_collection import PointCollection
297
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
298
sage: c = PointCollection(c.rays(), c.lattice())
299
sage: for point in c: print point
300
N(0, 0, 1)
301
N(1, 0, 1)
302
N(0, 1, 1)
303
N(1, 1, 1)
304
"""
305
return iter(self._points)
306
307
def __len__(self):
308
r"""
309
Return the number of points in ``self``.
310
311
OUTPUT:
312
313
- an integer.
314
315
EXAMPLES::
316
317
sage: from sage.geometry.point_collection import PointCollection
318
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
319
sage: c = PointCollection(c.rays(), c.lattice())
320
sage: len(c)
321
4
322
"""
323
return len(self._points)
324
325
def __reduce__(self):
326
r"""
327
Prepare ``self`` for pickling.
328
329
OUTPUT:
330
331
- a tuple, currently the class name and a tuple consisting of points
332
and the ambient module.
333
334
TESTS::
335
336
sage: from sage.geometry.point_collection import PointCollection
337
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
338
sage: c = PointCollection(c.rays(), c.lattice())
339
sage: loads(dumps(c))
340
[0 1 0 1]
341
[0 0 1 1]
342
[1 1 1 1]
343
in 3-d lattice N
344
sage: loads(dumps(c)) == c
345
True
346
"""
347
return (PointCollection, (self._points, self._module))
348
349
def _latex_(self):
350
r"""
351
Return a LaTeX representation of ``self``.
352
353
OUTPUT:
354
355
- a string.
356
357
TESTS::
358
359
sage: from sage.geometry.point_collection import PointCollection
360
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
361
sage: c = PointCollection(c.rays(), c.lattice())
362
sage: print c._latex_()
363
\left(\begin{array}{rrrr}
364
0 & 1 & 0 & 1 \\
365
0 & 0 & 1 & 1 \\
366
1 & 1 & 1 & 1
367
\end{array}\right)_{N}
368
"""
369
return r"%s_{%s}" % (latex(self.matrix()), latex(self.module()))
370
371
def _repr_(self):
372
r"""
373
Return a string representation of ``self``.
374
375
OUTPUT:
376
377
- a string.
378
379
TESTS::
380
381
sage: from sage.geometry.point_collection import PointCollection
382
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
383
sage: c = PointCollection(c.rays(), c.lattice())
384
sage: print c._repr_()
385
[0 1 0 1]
386
[0 0 1 1]
387
[1 1 1 1]
388
in 3-d lattice N
389
"""
390
return "%s\nin %s" % (self.matrix(), self.module())
391
392
def basis(self):
393
r"""
394
Return a linearly independent subset of points of ``self``.
395
396
OUTPUT:
397
398
- a :class:`point collection <PointCollection>` giving a random (but
399
fixed) choice of an `\RR`-basis for the vector space spanned by the
400
points of ``self``.
401
402
EXAMPLES::
403
404
sage: from sage.geometry.point_collection import PointCollection
405
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
406
sage: c = PointCollection(c.rays(), c.lattice())
407
sage: c.basis()
408
[0 1 0]
409
[0 0 1]
410
[1 1 1]
411
in 3-d lattice N
412
413
Calling this method twice will always return *exactly the same* point
414
collection::
415
416
sage: c.basis().basis() is c.basis()
417
True
418
"""
419
if self._basis is None:
420
self._basis = self(self.matrix().pivots())
421
return self._basis
422
423
def cardinality(self):
424
r"""
425
Return the number of points in ``self``.
426
427
OUTPUT:
428
429
- an integer.
430
431
EXAMPLES::
432
433
sage: from sage.geometry.point_collection import PointCollection
434
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
435
sage: c = PointCollection(c.rays(), c.lattice())
436
sage: c.cardinality()
437
4
438
"""
439
return len(self._points)
440
441
def cartesian_product(self, other, module=None):
442
r"""
443
Return the Cartesian product of ``self`` with ``other``.
444
445
INPUT:
446
447
- ``other`` -- a :class:`point collection <PointCollection>`;
448
449
- ``module`` -- (optional) the ambient module for the result. By
450
default, the direct sum of the ambient modules of ``self`` and
451
``other`` is constructed.
452
453
OUTPUT:
454
455
- a :class:`point collection <PointCollection>`.
456
457
EXAMPLES::
458
459
sage: from sage.geometry.point_collection import PointCollection
460
sage: c = Cone([(0,0,1), (1,1,1)])
461
sage: c = PointCollection(c.rays(), c.lattice())
462
sage: c.cartesian_product(c)
463
[0 1 0 1]
464
[0 1 0 1]
465
[1 1 1 1]
466
[0 0 1 1]
467
[0 0 1 1]
468
[1 1 1 1]
469
in 6-d lattice N+N
470
"""
471
assert is_PointCollection(other)
472
if module is None:
473
module = self._module.direct_sum(other.module())
474
P = [list(p) for p in self]
475
Q = [list(q) for q in other]
476
PQ = [module(p + q) for q in Q for p in P]
477
for pq in PQ:
478
pq.set_immutable()
479
return PointCollection(PQ, module)
480
481
def dimension(self):
482
r"""
483
Return the dimension of the space spanned by points of ``self``.
484
485
.. note:: You can use either :meth:`dim` or :meth:`dimension`.
486
487
OUTPUT:
488
489
- an integer.
490
491
EXAMPLES::
492
493
sage: from sage.geometry.point_collection import PointCollection
494
sage: c = Cone([(0,0,1), (1,1,1)])
495
sage: c = PointCollection(c.rays(), c.lattice())
496
sage: c.dimension()
497
2
498
sage: c.dim()
499
2
500
"""
501
return self.matrix().rank()
502
503
dim = dimension
504
505
def dual_module(self):
506
r"""
507
Return the dual of the ambient module of ``self``.
508
509
OUTPUT:
510
511
- a :class:`module <FreeModule_generic>`. If possible (that is, if the
512
ambient :meth:`module` `M` of ``self`` has a ``dual()`` method), the
513
dual module is returned. Otherwise, `R^n` is returned, where `n` is
514
the dimension of `M` and `R` is its base ring.
515
516
EXAMPLES::
517
518
sage: from sage.geometry.point_collection import PointCollection
519
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
520
sage: c = PointCollection(c.rays(), c.lattice())
521
sage: c.dual_module()
522
3-d lattice M
523
"""
524
M = self._module
525
try:
526
return M.dual()
527
except AttributeError:
528
# TODO: add support for torsion modules as well?
529
return M.base_ring() ** M.dimension()
530
531
def matrix(self):
532
r"""
533
Return a matrix whose columns are points of ``self``.
534
535
OUTPUT:
536
537
- a :class:`matrix <Matrix>`.
538
539
EXAMPLES::
540
541
sage: from sage.geometry.point_collection import PointCollection
542
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
543
sage: c = PointCollection(c.rays(), c.lattice())
544
sage: c.matrix()
545
[0 1 0 1]
546
[0 0 1 1]
547
[1 1 1 1]
548
"""
549
if self._matrix is None:
550
M = column_matrix(self._module.base_ring(), len(self._points),
551
self._module.degree(), self._points)
552
M.set_immutable()
553
self._matrix = M
554
return self._matrix
555
556
def module(self):
557
r"""
558
Return the ambient module of ``self``.
559
560
OUTPUT:
561
562
- a :class:`module <FreeModule_generic>`.
563
564
EXAMPLES::
565
566
sage: from sage.geometry.point_collection import PointCollection
567
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
568
sage: c = PointCollection(c.rays(), c.lattice())
569
sage: c.module()
570
3-d lattice N
571
"""
572
return self._module
573
574
def set(self):
575
r"""
576
Return points of ``self`` as a :class:`frozenset`.
577
578
OUTPUT:
579
580
- a :class:`frozenset`.
581
582
EXAMPLES::
583
584
sage: from sage.geometry.point_collection import PointCollection
585
sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)])
586
sage: c = PointCollection(c.rays(), c.lattice())
587
sage: c.set()
588
frozenset([N(0, 1, 1), N(1, 1, 1), N(0, 0, 1), N(1, 0, 1)])
589
"""
590
if self._set is None:
591
self._set = frozenset(self._points)
592
return self._set
593
594