Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/geometry/triangulation/base.pyx
4072 views
1
r"""
2
Base classes for triangulations
3
4
We provide (fast) cython implementations here.
5
6
AUTHORS:
7
8
- Volker Braun (2010-09-14): initial version.
9
"""
10
11
12
########################################################################
13
# Copyright (C) 2010 Volker Braun <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# http://www.gnu.org/licenses/
18
########################################################################
19
20
21
22
from sage.structure.sage_object cimport SageObject
23
from sage.structure.parent cimport Parent
24
from sage.categories.sets_cat import Sets
25
from sage.matrix.constructor import matrix
26
from sage.misc.misc import uniq
27
from sage.misc.cachefunc import cached_method
28
29
from functions cimport binomial
30
from triangulations cimport \
31
triangulations_ptr, init_triangulations, next_triangulation, delete_triangulations
32
33
34
########################################################################
35
cdef class Point(SageObject):
36
r"""
37
A point of a point configuration.
38
39
Note that the coordinates of the points of a point configuration
40
are somewhat arbitrary. What counts are the abstract linear
41
relations between the points, for example encoded by the
42
:meth:`~sage.geometry.triangulation.point_configuration.PointConfiguration.circuits`.
43
44
.. Warning::
45
46
You should not create :class:`Point` objects manually. The
47
constructor of :class:`PointConfiguration_base` takes care of
48
this for you.
49
50
INPUT:
51
52
- ``point_configuration`` -- :class:`PointConfiguration_base`. The
53
point configuration to which the point belongs.
54
55
- ``i`` -- integer. The index of the point in the point
56
configuration.
57
58
- ``projective`` -- the projective coordinates of the point.
59
60
- ``affine`` -- the affine coordinates of the point.
61
62
- ``reduced`` -- the reduced (with linearities removed)
63
coordinates of the point.
64
65
EXAMPLES::
66
67
sage: pc = PointConfiguration([(0,0)])
68
sage: from sage.geometry.triangulation.base import Point
69
sage: Point(pc, 123, (0,0,1), (0,0), ())
70
P(0, 0)
71
"""
72
73
cdef int _index
74
cdef tuple _projective, _affine, _reduced_affine
75
cdef object _point_configuration
76
cdef object _reduced_affine_vector, _reduced_projective_vector
77
78
79
def __init__(self, point_configuration, i, projective, affine, reduced):
80
r"""
81
Construct a :class:`Point`.
82
83
EXAMPLES::
84
85
sage: pc = PointConfiguration([(0,0)])
86
sage: from sage.geometry.triangulation.base import Point
87
sage: Point(pc, 123, (0,0,1), (0,0), ()) # indirect doctest
88
P(0, 0)
89
"""
90
self._index = i
91
self._projective = tuple(projective)
92
self._affine = tuple(affine)
93
self._reduced_affine = tuple(reduced)
94
self._point_configuration = point_configuration
95
V = point_configuration.reduced_affine_vector_space()
96
self._reduced_affine_vector = V(self._reduced_affine)
97
P = point_configuration.reduced_projective_vector_space()
98
self._reduced_projective_vector = P(self.reduced_projective())
99
100
101
cpdef point_configuration(self):
102
r"""
103
Return the point configuration to which the point belongs.
104
105
OUTPUT:
106
107
A :class:`~sage.geometry.triangulation.point_configuration.PointConfiguration`.
108
109
EXAMPLES:
110
111
sage: pc = PointConfiguration([ (0,0), (1,0), (0,1) ])
112
sage: p = pc.point(0)
113
sage: p is pc.point(0)
114
True
115
sage: p.point_configuration() is pc
116
True
117
"""
118
return self._point_configuration
119
120
121
def __iter__(self):
122
r"""
123
Iterate through the affine ambient space coordinates of the point.
124
125
EXAMPLES::
126
127
sage: pc = PointConfiguration([(0,0)])
128
sage: from sage.geometry.triangulation.base import Point
129
sage: p = Point(pc, 123, (1,2,1), (3,4), ())
130
sage: list(p) # indirect doctest
131
[3, 4]
132
"""
133
return self._affine.__iter__()
134
135
136
def __len__(self):
137
r"""
138
Return the affine ambient space dimension.
139
140
EXAMPLES::
141
142
sage: pc = PointConfiguration([(0,0)])
143
sage: from sage.geometry.triangulation.base import Point
144
sage: p = Point(pc, 123, (1,2,1), (3,4), ())
145
sage: len(p)
146
2
147
sage: p.__len__()
148
2
149
"""
150
return len(self._affine)
151
152
153
cpdef index(self):
154
"""
155
Return the index of the point in the point configuration.
156
157
EXAMPLES::
158
159
sage: pc = PointConfiguration([[0, 1], [0, 0], [1, 0]])
160
sage: p = pc.point(2); p
161
P(1, 0)
162
sage: p.index()
163
2
164
"""
165
return self._index
166
167
168
cpdef projective(self):
169
r"""
170
Return the projective coordinates of the point in the ambient space.
171
172
OUTPUT:
173
174
A tuple containing the coordinates.
175
176
EXAMPLES::
177
178
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
179
sage: p = pc.point(2); p
180
P(10, 2, 3)
181
sage: p.affine()
182
(10, 2, 3)
183
sage: p.projective()
184
(10, 2, 3, 1)
185
sage: p.reduced_affine()
186
(2, 2)
187
sage: p.reduced_projective()
188
(2, 2, 1)
189
sage: p.reduced_affine_vector()
190
(2, 2)
191
"""
192
return self._projective
193
194
195
cpdef affine(self):
196
r"""
197
Return the affine coordinates of the point in the ambient space.
198
199
OUTPUT:
200
201
A tuple containing the coordinates.
202
203
EXAMPLES::
204
205
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
206
sage: p = pc.point(2); p
207
P(10, 2, 3)
208
sage: p.affine()
209
(10, 2, 3)
210
sage: p.projective()
211
(10, 2, 3, 1)
212
sage: p.reduced_affine()
213
(2, 2)
214
sage: p.reduced_projective()
215
(2, 2, 1)
216
sage: p.reduced_affine_vector()
217
(2, 2)
218
"""
219
return self._affine
220
221
222
cpdef reduced_affine(self):
223
r"""
224
Return the affine coordinates of the point on the hyperplane
225
spanned by the point configuration.
226
227
OUTPUT:
228
229
A tuple containing the coordinates.
230
231
EXAMPLES::
232
233
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
234
sage: p = pc.point(2); p
235
P(10, 2, 3)
236
sage: p.affine()
237
(10, 2, 3)
238
sage: p.projective()
239
(10, 2, 3, 1)
240
sage: p.reduced_affine()
241
(2, 2)
242
sage: p.reduced_projective()
243
(2, 2, 1)
244
sage: p.reduced_affine_vector()
245
(2, 2)
246
"""
247
return self._reduced_affine
248
249
250
cpdef reduced_projective(self):
251
r"""
252
Return the projective coordinates of the point on the hyperplane
253
spanned by the point configuration.
254
255
OUTPUT:
256
257
A tuple containing the coordinates.
258
259
EXAMPLES::
260
261
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
262
sage: p = pc.point(2); p
263
P(10, 2, 3)
264
sage: p.affine()
265
(10, 2, 3)
266
sage: p.projective()
267
(10, 2, 3, 1)
268
sage: p.reduced_affine()
269
(2, 2)
270
sage: p.reduced_projective()
271
(2, 2, 1)
272
sage: p.reduced_affine_vector()
273
(2, 2)
274
"""
275
return tuple(self._reduced_affine)+(1,)
276
277
278
cpdef reduced_affine_vector(self):
279
"""
280
Return the affine coordinates of the point on the hyperplane
281
spanned by the point configuration.
282
283
OUTPUT:
284
285
A tuple containing the coordinates.
286
287
EXAMPLES::
288
289
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
290
sage: p = pc.point(2); p
291
P(10, 2, 3)
292
sage: p.affine()
293
(10, 2, 3)
294
sage: p.projective()
295
(10, 2, 3, 1)
296
sage: p.reduced_affine()
297
(2, 2)
298
sage: p.reduced_projective()
299
(2, 2, 1)
300
sage: p.reduced_affine_vector()
301
(2, 2)
302
"""
303
return self._reduced_affine_vector
304
305
306
cpdef reduced_projective_vector(self):
307
"""
308
Return the affine coordinates of the point on the hyperplane
309
spanned by the point configuration.
310
311
OUTPUT:
312
313
A tuple containing the coordinates.
314
315
EXAMPLES::
316
317
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0], [10, 2, 3]])
318
sage: p = pc.point(2); p
319
P(10, 2, 3)
320
sage: p.affine()
321
(10, 2, 3)
322
sage: p.projective()
323
(10, 2, 3, 1)
324
sage: p.reduced_affine()
325
(2, 2)
326
sage: p.reduced_projective()
327
(2, 2, 1)
328
sage: p.reduced_affine_vector()
329
(2, 2)
330
sage: type(p.reduced_affine_vector())
331
<type 'sage.modules.vector_rational_dense.Vector_rational_dense'>
332
"""
333
return self._reduced_projective_vector
334
335
336
cpdef _repr_(self):
337
"""
338
Return a string representation of the point.
339
340
OUTPUT:
341
342
String.
343
344
EXAMPLES::
345
346
sage: pc = PointConfiguration([[10, 0, 1], [10, 0, 0]])
347
sage: from sage.geometry.triangulation.base import Point
348
sage: p = Point(pc, 123, (0,0,1), (0,0), (0,))
349
sage: p._repr_()
350
'P(0, 0)'
351
"""
352
return 'P'+str(self._affine)
353
354
355
########################################################################
356
cdef class PointConfiguration_base(Parent):
357
r"""
358
The cython abstract base class for
359
:class:`~sage.geometry.triangulation.PointConfiguration`.
360
361
.. WARNING::
362
363
You should not instantiate this base class, but only its
364
derived class
365
:class:`~sage.geometry.triangulation.point_configuration.PointConfiguration`.
366
"""
367
368
def __init__(self, points, defined_affine):
369
r"""
370
Construct a :class:`PointConfiguration_base`.
371
372
INPUT:
373
374
- ``points`` -- a tuple of tuples of projective coordinates
375
with ``1`` as the final coordinate.
376
377
- ``defined_affine`` -- Boolean. Whether the point
378
configuration is defined as a configuration of affine (as
379
opposed to projective) points.
380
381
TESTS::
382
383
sage: from sage.geometry.triangulation.base import PointConfiguration_base
384
sage: PointConfiguration_base(((1,2,1),(2,3,1),(3,4,1)), False) # indirect doctest
385
<type 'sage.geometry.triangulation.base.PointConfiguration_base'>
386
"""
387
Parent.__init__(self, category = Sets())
388
self._init_points(points)
389
self._is_affine = defined_affine
390
391
392
cdef tuple _pts
393
cdef int _ambient_dim
394
cdef int _dim
395
cdef object _base_ring
396
cdef bint _is_affine
397
cdef object _reduced_affine_vector_space, _reduced_projective_vector_space
398
399
400
cdef _init_points(self, tuple projective_points):
401
"""
402
Internal method to determine coordinates of points.
403
404
EXAMPLES::
405
406
sage: p = PointConfiguration([[0, 1], [0, 0], [1, 0]]) # indirect doctest
407
sage: p.points()
408
(P(0, 1), P(0, 0), P(1, 0))
409
410
Special cases::
411
412
sage: PointConfiguration([])
413
A point configuration in QQ^0 consisting of 0 points. The
414
triangulations of this point configuration are assumed to
415
be connected, not necessarily fine, not necessarily regular.
416
sage: PointConfiguration([(1,2,3)])
417
A point configuration in QQ^3 consisting of 1 point. The
418
triangulations of this point configuration are assumed to
419
be connected, not necessarily fine, not necessarily regular.
420
"""
421
n = len(projective_points)
422
if n==0:
423
self._ambient_dim = 0
424
self._dim = -1
425
self._pts = tuple()
426
return
427
428
# We now are sure that projective_points is not empty
429
self._ambient_dim = len(projective_points[0])-1
430
assert all([ len(p)==self._ambient_dim+1 for p in projective_points ]), \
431
'The given point coordinates must all have the same length.'
432
assert len(uniq(projective_points)) == len(projective_points), \
433
'Not all points are pairwise distinct.'
434
435
proj = matrix(projective_points).transpose()
436
self._base_ring = proj.base_ring()
437
438
if all([ x==1 for x in proj.row(self.ambient_dim()) ]):
439
aff = proj.submatrix(0,0,nrows=self.ambient_dim())
440
else:
441
raise NotImplementedError # TODO
442
443
if n>1:
444
# shift first point to origin
445
red = matrix([ aff.column(i)-aff.column(0) for i in range(0,n) ]).transpose()
446
# pick linearly independent rows
447
red = matrix([ red.row(i) for i in red.pivot_rows()])
448
else:
449
red = matrix(0,1)
450
self._dim = red.nrows()
451
452
from sage.modules.free_module import VectorSpace
453
self._reduced_affine_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim)
454
self._reduced_projective_vector_space = VectorSpace(self._base_ring.fraction_field(), self._dim+1)
455
self._pts = tuple([ Point(self, i, proj.column(i), aff.column(i), red.column(i))
456
for i in range(0,n) ])
457
458
459
cpdef reduced_affine_vector_space(self):
460
"""
461
Return the vector space that contains the affine points.
462
463
OUTPUT:
464
465
A vector space over the fraction field of :meth:`base_ring`.
466
467
EXAMPLES::
468
469
sage: p = PointConfiguration([[0,0,0], [1,2,3]])
470
sage: p.base_ring()
471
Integer Ring
472
sage: p.reduced_affine_vector_space()
473
Vector space of dimension 1 over Rational Field
474
sage: p.reduced_projective_vector_space()
475
Vector space of dimension 2 over Rational Field
476
"""
477
return self._reduced_affine_vector_space
478
479
480
cpdef reduced_projective_vector_space(self):
481
"""
482
Return the vector space that is spanned by the homogeneous
483
coordinates.
484
485
OUTPUT:
486
487
A vector space over the fraction field of :meth:`base_ring`.
488
489
EXAMPLES::
490
491
sage: p = PointConfiguration([[0,0,0], [1,2,3]])
492
sage: p.base_ring()
493
Integer Ring
494
sage: p.reduced_affine_vector_space()
495
Vector space of dimension 1 over Rational Field
496
sage: p.reduced_projective_vector_space()
497
Vector space of dimension 2 over Rational Field
498
"""
499
return self._reduced_projective_vector_space
500
501
502
cpdef ambient_dim(self):
503
"""
504
Return the dimension of the ambient space of the point
505
configuration.
506
507
See also :meth:`dimension`
508
509
EXAMPLES::
510
511
sage: p = PointConfiguration([[0,0,0]])
512
sage: p.ambient_dim()
513
3
514
sage: p.dim()
515
0
516
"""
517
return self._ambient_dim
518
519
520
cpdef dim(self):
521
"""
522
Return the actual dimension of the point
523
configuration.
524
525
See also :meth:`ambient_dim`
526
527
EXAMPLES::
528
529
sage: p = PointConfiguration([[0,0,0]])
530
sage: p.ambient_dim()
531
3
532
sage: p.dim()
533
0
534
"""
535
return self._dim
536
537
538
cpdef base_ring(self):
539
r"""
540
Return the base ring, that is, the ring containing the
541
coordinates of the points.
542
543
OUTPUT:
544
545
A ring.
546
547
EXAMPLES::
548
549
sage: p = PointConfiguration([(0,0)])
550
sage: p.base_ring()
551
Integer Ring
552
553
sage: p = PointConfiguration([(1/2,3)])
554
sage: p.base_ring()
555
Rational Field
556
557
sage: p = PointConfiguration([(0.2, 5)])
558
sage: p.base_ring()
559
Real Field with 53 bits of precision
560
"""
561
return self._base_ring
562
563
564
cpdef bint is_affine(self):
565
"""
566
Whether the configuration is defined by affine points.
567
568
OUTPUT:
569
570
Boolean. If true, the homogeneous coordinates all have `1` as
571
their last entry.
572
573
EXAMPLES::
574
575
sage: p = PointConfiguration([(0.2, 5), (3, 0.1)])
576
sage: p.is_affine()
577
True
578
579
sage: p = PointConfiguration([(0.2, 5, 1), (3, 0.1, 1)], projective=True)
580
sage: p.is_affine()
581
False
582
"""
583
return self._is_affine
584
585
586
def _assert_is_affine(self):
587
"""
588
Raise a ``ValueError`` if the point configuration is not
589
defined by affine points.
590
591
EXAMPLES::
592
593
sage: p = PointConfiguration([(0.2, 5), (3, 0.1)])
594
sage: p._assert_is_affine()
595
sage: p = PointConfiguration([(0.2, 5, 1), (3, 0.1, 1)], projective=True)
596
sage: p._assert_is_affine()
597
Traceback (most recent call last):
598
...
599
ValueError: The point configuration contains projective points.
600
"""
601
if not self.is_affine():
602
raise ValueError('The point configuration contains projective points.')
603
604
605
def __getitem__(self, i):
606
"""
607
Return the ``i``-th point.
608
609
Same as :meth:`point`.
610
611
INPUT:
612
613
- ``i`` -- integer.
614
615
OUTPUT:
616
617
The ``i``-th point of the point configuration.
618
619
EXAMPLES::
620
621
sage: p = PointConfiguration([[1,0], [2,3], [3,2]])
622
sage: [ p[i] for i in range(0,p.n_points()) ]
623
[P(1, 0), P(2, 3), P(3, 2)]
624
sage: list(p)
625
[P(1, 0), P(2, 3), P(3, 2)]
626
sage: list(p.points())
627
[P(1, 0), P(2, 3), P(3, 2)]
628
sage: [ p.point(i) for i in range(0,p.n_points()) ]
629
[P(1, 0), P(2, 3), P(3, 2)]
630
"""
631
return self._pts[i]
632
633
634
cpdef n_points(self):
635
"""
636
Return the number of points.
637
638
Same as ``len(self)``.
639
640
EXAMPLES::
641
642
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
643
sage: p
644
A point configuration in QQ^2 consisting of 5 points. The
645
triangulations of this point configuration are assumed to
646
be connected, not necessarily fine, not necessarily regular.
647
sage: len(p)
648
5
649
sage: p.n_points()
650
5
651
"""
652
return len(self._pts)
653
654
655
cpdef points(self):
656
"""
657
Return a list of the points.
658
659
OUTPUT:
660
661
Returns a list of the points. See also the :meth:`__iter__`
662
method, which returns the corresponding generator.
663
664
EXAMPLES::
665
666
sage: pconfig = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
667
sage: list(pconfig)
668
[P(0, 0), P(0, 1), P(1, 0), P(1, 1), P(-1, -1)]
669
sage: [ p for p in pconfig.points() ]
670
[P(0, 0), P(0, 1), P(1, 0), P(1, 1), P(-1, -1)]
671
sage: pconfig.point(0)
672
P(0, 0)
673
sage: pconfig.point(1)
674
P(0, 1)
675
sage: pconfig.point( pconfig.n_points()-1 )
676
P(-1, -1)
677
"""
678
return self._pts
679
680
681
def point(self, i):
682
"""
683
Return the i-th point of the configuration.
684
685
Same as :meth:`__getitem__`
686
687
INPUT:
688
689
- ``i`` -- integer.
690
691
OUTPUT:
692
693
A point of the point configuration.
694
695
EXAMPLES::
696
697
sage: pconfig = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
698
sage: list(pconfig)
699
[P(0, 0), P(0, 1), P(1, 0), P(1, 1), P(-1, -1)]
700
sage: [ p for p in pconfig.points() ]
701
[P(0, 0), P(0, 1), P(1, 0), P(1, 1), P(-1, -1)]
702
sage: pconfig.point(0)
703
P(0, 0)
704
sage: pconfig[0]
705
P(0, 0)
706
sage: pconfig.point(1)
707
P(0, 1)
708
sage: pconfig.point( pconfig.n_points()-1 )
709
P(-1, -1)
710
"""
711
return self._pts[i]
712
713
714
def __len__(self):
715
"""
716
Return the number of points.
717
718
Same as :meth:`n_points`
719
720
EXAMPLES::
721
722
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
723
sage: p
724
A point configuration in QQ^2 consisting of 5 points. The
725
triangulations of this point configuration are assumed to
726
be connected, not necessarily fine, not necessarily regular.
727
sage: len(p)
728
5
729
sage: p.n_points()
730
5
731
"""
732
return len(self._pts)
733
734
735
cpdef simplex_to_int(self, simplex):
736
r"""
737
Returns an integer that uniquely identifies the given simplex.
738
739
See also the inverse method :meth:`int_to_simplex`.
740
741
The enumeration is compatible with [PUNTOS]_.
742
743
INPUT:
744
745
- ``simplex`` -- iterable, for example a list. The elements
746
are the vertex indices of the simplex.
747
748
OUTPUT:
749
750
An integer that uniquely specifies the simplex.
751
752
EXAMPLES::
753
754
sage: U=matrix([
755
... [ 0, 0, 0, 0, 0, 2, 4,-1, 1, 1, 0, 0, 1, 0],
756
... [ 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0],
757
... [ 0, 2, 0, 0, 0, 0,-1, 0, 1, 0, 1, 0, 0, 1],
758
... [ 0, 1, 1, 0, 0, 1, 0,-2, 1, 0, 0,-1, 1, 1],
759
... [ 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0]
760
... ])
761
sage: pc = PointConfiguration(U.columns())
762
sage: pc.simplex_to_int([1,3,4,7,10,13])
763
1678
764
sage: pc.int_to_simplex(1678)
765
(1, 3, 4, 7, 10, 13)
766
"""
767
cdef int s = 1
768
cdef int k = 1
769
cdef int n = self.n_points()
770
cdef int d = len(simplex)
771
assert d==self.dim()+1
772
cdef int i, j
773
for i in range(1,d+1):
774
l = simplex[i-1]+1
775
for j in range(k,l):
776
s += binomial(n-j,d-i)
777
k = l+1
778
return s
779
780
781
cpdef int_to_simplex(self, int s):
782
r"""
783
Reverses the enumeration of possible simplices in
784
:meth:`simplex_to_int`.
785
786
The enumeration is compatible with [PUNTOS]_.
787
788
INPUT:
789
790
- ``s`` -- int. An integer that uniquely specifies a simplex.
791
792
OUTPUT:
793
794
An ordered tuple consisting of the indices of the vertices of
795
the simplex.
796
797
EXAMPLES::
798
799
sage: U=matrix([
800
... [ 0, 0, 0, 0, 0, 2, 4,-1, 1, 1, 0, 0, 1, 0],
801
... [ 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0],
802
... [ 0, 2, 0, 0, 0, 0,-1, 0, 1, 0, 1, 0, 0, 1],
803
... [ 0, 1, 1, 0, 0, 1, 0,-2, 1, 0, 0,-1, 1, 1],
804
... [ 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0]
805
... ])
806
sage: pc = PointConfiguration(U.columns())
807
sage: pc.simplex_to_int([1,3,4,7,10,13])
808
1678
809
sage: pc.int_to_simplex(1678)
810
(1, 3, 4, 7, 10, 13)
811
"""
812
simplex = []
813
cdef int l = 0
814
cdef int n = self.n_points()
815
cdef int d = self.dim()+1
816
cdef int k, b
817
for k in range(1,d):
818
l += 1
819
i = l
820
j = 1
821
b = binomial(n-l,d-k)
822
while (s>b) and (b>0):
823
j += 1
824
l += 1
825
s -= b
826
b = binomial(n-l,d-k)
827
simplex.append(l-1)
828
simplex.append(s+l-1)
829
assert len(simplex) == d
830
return tuple(simplex)
831
832
833
834
########################################################################
835
cdef class ConnectedTriangulationsIterator(SageObject):
836
r"""
837
A Python shim for the C++-class 'triangulations'
838
839
INPUT:
840
841
- ``point_configuration`` -- a
842
:class:`~sage.geometry.triangulation.point_configuration.PointConfiguration`.
843
844
- ``seed`` -- a regular triangulation or ``None`` (default). In
845
the latter case, a suitable triangulation is generated
846
automatically. Otherwise, you can explicitly specify the seed
847
triangulation as
848
849
* A
850
:class:`~sage.geometry.triangulation.element.Triangulation`
851
object, or
852
853
* an iterable of iterables specifying the vertices of the simplices, or
854
855
* an iterable of integers, which are then considered the
856
enumerated simplices (see
857
:meth:`~PointConfiguration_base.simplex_to_int`.
858
859
- ``star`` -- either ``None`` (default) or an integer. If an
860
integer is passed, all returned triangulations will be star with
861
respect to the
862
863
- ``fine`` -- boolean (default: ``False``). Whether to return only
864
fine triangulations, that is, simplicial decompositions that
865
make use of all the points of the configuration.
866
867
OUTPUT:
868
869
An iterator. The generated values are tuples of
870
integers, which encode simplices of the triangulation. The output
871
is a suitable input to
872
:class:`~sage.geometry.triangulation.element.Triangulation`.
873
874
EXAMPLES::
875
876
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
877
sage: from sage.geometry.triangulation.base import ConnectedTriangulationsIterator
878
sage: ci = ConnectedTriangulationsIterator(p)
879
sage: ci.next()
880
(9, 10)
881
sage: ci.next()
882
(2, 3, 4, 5)
883
sage: ci.next()
884
(7, 8)
885
sage: ci.next()
886
(1, 3, 5, 7)
887
sage: ci.next()
888
Traceback (most recent call last):
889
...
890
StopIteration
891
892
You can reconstruct the triangulation from the compressed output via::
893
894
sage: from sage.geometry.triangulation.element import Triangulation
895
sage: Triangulation((2, 3, 4, 5), p)
896
(<0,1,3>, <0,1,4>, <0,2,3>, <0,2,4>)
897
898
How to use the restrictions::
899
900
sage: ci = ConnectedTriangulationsIterator(p, fine=True)
901
sage: list(ci)
902
[(2, 3, 4, 5), (1, 3, 5, 7)]
903
sage: ci = ConnectedTriangulationsIterator(p, star=1)
904
sage: list(ci)
905
[(7, 8)]
906
sage: ci = ConnectedTriangulationsIterator(p, star=1, fine=True)
907
sage: list(ci)
908
[]
909
"""
910
911
cdef triangulations_ptr _tp
912
913
914
def __cinit__(self):
915
"""
916
The Cython constructor.
917
918
TESTS::
919
920
sage: from sage.geometry.triangulation.base import ConnectedTriangulationsIterator
921
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
922
sage: ConnectedTriangulationsIterator(p, fine=True) # indirect doctest
923
<type 'sage.geometry.triangulation.base.ConnectedTriangulationsIterator'>
924
"""
925
self._tp = NULL
926
927
928
def __init__(self, point_configuration, seed=None, star=None, fine=False):
929
r"""
930
The Python constructor.
931
932
See :class:`ConnectedTriangulationsIterator` for a description
933
of the arguments.
934
935
TESTS::
936
937
sage: p = PointConfiguration([[0,4],[2,3],[3,2],[4,0],[3,-2],[2,-3],[0,-4],[-2,-3],[-3,-2],[-4,0],[-3,2],[-2,3]])
938
sage: from sage.geometry.triangulation.base import ConnectedTriangulationsIterator
939
sage: ci = ConnectedTriangulationsIterator(p)
940
sage: len(list(ci)) # long time (23s on sage.math, 2011)
941
16796
942
sage: ci = ConnectedTriangulationsIterator(p, star=3)
943
sage: len(list(ci)) # long time (23s on sage.math, 2011)
944
1
945
"""
946
if star==None:
947
star = -1
948
if seed==None:
949
seed = point_configuration.lexicographic_triangulation().enumerate_simplices()
950
try:
951
enumerated_simplices_seed = seed.enumerated_simplices()
952
except AttributeError:
953
enumerated_simplices_seed = tuple([ int(t) for t in seed ])
954
assert self._tp == NULL
955
self._tp = init_triangulations(point_configuration.n_points(),
956
point_configuration.dim()+1,
957
star, fine,
958
enumerated_simplices_seed,
959
point_configuration.bistellar_flips())
960
961
962
def __dealloc__(self):
963
r"""
964
The Cython destructor.
965
"""
966
delete_triangulations(self._tp)
967
968
969
def __iter__(self):
970
r"""
971
The iterator interface: Start iterating.
972
973
TESTS::
974
975
sage: from sage.geometry.triangulation.base import ConnectedTriangulationsIterator
976
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
977
sage: ci = ConnectedTriangulationsIterator(p, fine=True)
978
sage: ci.__iter__()
979
<type 'sage.geometry.triangulation.base.ConnectedTriangulationsIterator'>
980
sage: ci.__iter__() is ci
981
True
982
"""
983
return self
984
985
986
def __next__(self):
987
r"""
988
The iterator interface: Next iteration.
989
990
EXAMPLES::
991
992
sage: from sage.geometry.triangulation.base import ConnectedTriangulationsIterator
993
sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]])
994
sage: ci = ConnectedTriangulationsIterator(p)
995
sage: ci.__next__()
996
(9, 10)
997
"""
998
t = next_triangulation(self._tp)
999
if len(t)==0:
1000
raise StopIteration
1001
return t
1002
1003
1004
1005
1006
1007