Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/homology/cell_complex.py
4082 views
1
r"""
2
Generic cell complexes
3
4
AUTHORS:
5
6
- John H. Palmieri (2009-08)
7
8
This module defines a class of abstract finite cell complexes. This
9
is meant as a base class from which other classes (like
10
:class:`~sage.homology.simplicial_complex.SimplicialComplex`,
11
:class:`~sage.homology.cubical_complex.CubicalComplex`, and
12
:class:`~sage.homology.delta_complex.DeltaComplex`) should derive. As
13
such, most of its properties are not implemented. It is meant for use
14
by developers producing new classes, not casual users.
15
16
.. note::
17
18
Keywords for :meth:`GenericCellComplex.chain_complex`,
19
:meth:`GenericCellComplex.homology`, etc.: any keywords given to
20
the :meth:`~GenericCellComplex.homology` method get passed on to
21
the :meth:`~GenericCellComplex.chain_complex` method and also to
22
the constructor for chain complexes in
23
:class:`~sage.homology.chain_complex.ChainComplex`, as well its
24
associated
25
:meth:`~sage.homology.chain_complex.ChainComplex.homology` method.
26
This means that those keywords should have consistent meaning in
27
all of those situations. It also means that it is easy to
28
implement new keywords: for example, if you implement a new
29
keyword for the
30
:meth:`sage.homology.chain_complex.ChainComplex.homology` method,
31
then it will be automatically accessible through the
32
:meth:`~GenericCellComplex.homology` method for cell complexes --
33
just make sure it gets documented.
34
"""
35
36
from sage.structure.sage_object import SageObject
37
from sage.rings.integer_ring import ZZ
38
from sage.rings.rational_field import QQ
39
40
class GenericCellComplex(SageObject):
41
r"""
42
Class of abstract cell complexes.
43
44
This is meant to be used by developers to produce new classes, not
45
by casual users. Classes which derive from this are
46
:class:`~sage.homology.simplicial_complex.SimplicialComplex`,
47
:class:`~sage.homology.delta_complex.DeltaComplex`, and
48
:class:`~sage.homology.cubical_complex.CubicalComplex`.
49
50
Most of the methods here are not implemented, but probably should
51
be implemented in a derived class. Most of the other methods call
52
a non-implemented one; their docstrings contain examples from
53
derived classes in which the various methods have been defined.
54
For example, :meth:`homology` calls :meth:`chain_complex`; the
55
class :class:`~sage.homology.delta_complex.DeltaComplex`
56
implements
57
:meth:`~sage.homology.delta_complex.DeltaComplex.chain_complex`,
58
and so the :meth:`homology` method here is illustrated with
59
examples involving `\Delta`-complexes.
60
61
EXAMPLES:
62
63
It's hard to give informative examples of the base class, since
64
essentially nothing is implemented. ::
65
66
sage: from sage.homology.cell_complex import GenericCellComplex
67
sage: A = GenericCellComplex()
68
"""
69
def __cmp__(self,right):
70
"""
71
Comparisons of cell complexes are not implemented.
72
73
EXAMPLES::
74
75
sage: from sage.homology.cell_complex import GenericCellComplex
76
sage: A = GenericCellComplex(); B = GenericCellComplex()
77
sage: A == B # indirect doctest
78
Traceback (most recent call last):
79
...
80
NotImplementedError
81
"""
82
raise NotImplementedError
83
84
############################################################
85
# self.cells() and related methods
86
############################################################
87
88
def cells(self, subcomplex=None):
89
"""
90
The cells of this cell complex, in the form of a dictionary:
91
the keys are integers, representing dimension, and the value
92
associated to an integer d is the set of d-cells. If the
93
optional argument ``subcomplex`` is present, then return only
94
the faces which are *not* in the subcomplex.
95
96
:param subcomplex: a subcomplex of this cell complex. Return
97
the cells which are not in this subcomplex.
98
:type subcomplex: optional, default None
99
100
This is not implemented in general; it should be implemented
101
in any derived class. When implementing, see the warning in
102
the :meth:`dimension` method.
103
104
This method is used by various other methods, such as
105
:meth:`n_cells` and :meth:`f_vector`.
106
107
EXAMPLES::
108
109
sage: from sage.homology.cell_complex import GenericCellComplex
110
sage: A = GenericCellComplex()
111
sage: A.cells()
112
Traceback (most recent call last):
113
...
114
NotImplementedError
115
"""
116
raise NotImplementedError
117
118
def dimension(self):
119
"""
120
The dimension of this cell complex: the maximum
121
dimension of its cells.
122
123
.. warning::
124
125
If the :meth:`cells` method calls :meth:`dimension`,
126
then you'll get an infinite loop. So either don't use
127
:meth:`dimension` or override :meth:`dimension`.
128
129
EXAMPLES::
130
131
sage: simplicial_complexes.RandomComplex(d=5, n=8).dimension()
132
5
133
sage: delta_complexes.Sphere(3).dimension()
134
3
135
sage: T = cubical_complexes.Torus()
136
sage: T.product(T).dimension()
137
4
138
"""
139
try:
140
return max([x.dimension() for x in self._facets])
141
except AttributeError:
142
return max(self.cells())
143
144
def n_cells(self, n, subcomplex=None):
145
"""
146
List of cells of dimension n of this cell complex.
147
If the optional argument ``subcomplex`` is present, then
148
return the ``n``-dimensional faces which are *not* in the
149
subcomplex.
150
151
:param n: the dimension
152
:type n: non-negative integer
153
:param subcomplex: a subcomplex of this cell complex. Return
154
the cells which are not in this subcomplex.
155
:type subcomplex: optional, default None
156
157
EXAMPLES::
158
159
sage: simplicial_complexes.Simplex(2).n_cells(1)
160
[(1, 2), (0, 2), (0, 1)]
161
sage: delta_complexes.Torus().n_cells(1)
162
[(0, 0), (0, 0), (0, 0)]
163
sage: cubical_complexes.Cube(1).n_cells(0)
164
[[1,1], [0,0]]
165
"""
166
if n in self.cells(subcomplex):
167
return list(self.cells(subcomplex)[n])
168
else:
169
# don't barf if someone asks for n_cells in a dimension where there are none
170
return []
171
172
def f_vector(self):
173
"""
174
The `f`-vector of this cell complex: a list whose `n^{th}`
175
item is the number of `(n-1)`-cells. Note that, like all
176
lists in Sage, this is indexed starting at 0: the 0th element
177
in this list is the number of `(-1)`-cells (which is 1: the
178
empty cell is the only `(-1)`-cell).
179
180
EXAMPLES::
181
182
sage: simplicial_complexes.KleinBottle().f_vector()
183
[1, 9, 27, 18]
184
sage: delta_complexes.KleinBottle().f_vector()
185
[1, 1, 3, 2]
186
sage: cubical_complexes.KleinBottle().f_vector()
187
[1, 42, 84, 42]
188
"""
189
return [self._f_dict()[n] for n in range(-1, self.dimension()+1)]
190
191
def _f_dict(self):
192
"""
193
The `f`-vector of this cell complex as a dictionary: the
194
item associated to an integer `n` is the number of the
195
`n`-cells.
196
197
EXAMPLES::
198
199
sage: simplicial_complexes.KleinBottle()._f_dict()[1]
200
27
201
sage: delta_complexes.KleinBottle()._f_dict()[1]
202
3
203
"""
204
answer = {}
205
answer[-1] = 1
206
for n in range(self.dimension() + 1):
207
answer[n] = len(self.n_cells(n))
208
return answer
209
210
def euler_characteristic(self):
211
r"""
212
The Euler characteristic of this cell complex: the
213
alternating sum over `n \geq 0` of the number of
214
`n`-cells.
215
216
EXAMPLES::
217
218
sage: simplicial_complexes.Simplex(5).euler_characteristic()
219
1
220
sage: delta_complexes.Sphere(6).euler_characteristic()
221
2
222
sage: cubical_complexes.KleinBottle().euler_characteristic()
223
0
224
"""
225
return sum([(-1)**n * self.f_vector()[n+1] for n in range(self.dimension() + 1)])
226
227
############################################################
228
# end of methods using self.cells()
229
############################################################
230
231
def product(self, right, rename_vertices=True):
232
"""
233
The (Cartesian) product of this cell complex with another one.
234
235
Products are not implemented for general cell complexes. They
236
may be implemented in some derived classes (like simplicial
237
complexes).
238
239
EXAMPLES::
240
241
sage: from sage.homology.cell_complex import GenericCellComplex
242
sage: A = GenericCellComplex(); B = GenericCellComplex()
243
sage: A.product(B)
244
Traceback (most recent call last):
245
...
246
NotImplementedError
247
"""
248
raise NotImplementedError
249
250
def disjoint_union(self, right):
251
"""
252
The disjoint union of this simplicial complex with another one.
253
254
:param right: the other simplicial complex (the right-hand factor)
255
256
Disjoint unions are not implemented for general cell complexes.
257
258
EXAMPLES::
259
260
sage: from sage.homology.cell_complex import GenericCellComplex
261
sage: A = GenericCellComplex(); B = GenericCellComplex()
262
sage: A.disjoint_union(B)
263
Traceback (most recent call last):
264
...
265
NotImplementedError
266
"""
267
raise NotImplementedError
268
269
def wedge(self, right):
270
"""
271
The wedge (one-point union) of this simplicial complex with
272
another one.
273
274
:param right: the other simplicial complex (the right-hand factor)
275
276
Wedges are not implemented for general cell complexes.
277
278
EXAMPLES::
279
280
sage: from sage.homology.cell_complex import GenericCellComplex
281
sage: A = GenericCellComplex(); B = GenericCellComplex()
282
sage: A.wedge(B)
283
Traceback (most recent call last):
284
...
285
NotImplementedError
286
"""
287
raise NotImplementedError
288
289
############################################################
290
# self.join() and related methods
291
############################################################
292
293
def join(self, right, **kwds):
294
"""
295
The join of this cell complex with another one.
296
297
:param right: the other simplicial complex (the right-hand factor)
298
299
Joins are not implemented for general cell complexes. They
300
may be implemented in some derived classes (like simplicial
301
complexes).
302
303
EXAMPLES::
304
305
sage: from sage.homology.cell_complex import GenericCellComplex
306
sage: A = GenericCellComplex(); B = GenericCellComplex()
307
sage: A.join(B)
308
Traceback (most recent call last):
309
...
310
NotImplementedError
311
"""
312
raise NotImplementedError
313
314
# for some classes, you may want * to mean join:
315
###
316
# __mul__ = join
317
318
# the cone on X is the join of X with a point. See
319
# simplicial_complex.py for one implementation.
320
###
321
# def cone(self):
322
# return self.join(POINT)
323
324
# the suspension of X is the join of X with the 0-sphere (two
325
# points). See simplicial_complex.py for one implementation.
326
###
327
# def suspension(self, n=1):
328
# """
329
# The suspension of this cell complex.
330
#
331
# INPUT:
332
#
333
# - ``n`` - positive integer (optional, default 1): suspend this
334
# many times.
335
# """
336
# raise NotImplementedError
337
338
############################################################
339
# end of methods using self.join()
340
############################################################
341
342
############################################################
343
# chain complexes, homology
344
############################################################
345
346
def chain_complex(self, **kwds):
347
"""
348
This is not implemented for general cell complexes.
349
350
Some keywords to possibly implement in a derived class:
351
352
- ``subcomplex`` - a subcomplex: compute the relative chain complex
353
- ``augmented`` - a bool: whether to return the augmented complex
354
- ``verbose`` - a bool: whether to print informational messages as
355
the chain complex is being computed
356
- ``check_diffs`` - a bool: whether to check that the each
357
composite of two consecutive differentials is zero
358
- ``dimensions`` - if None, compute the chain complex in all
359
dimensions. If a list or tuple of integers, compute the
360
chain complex in those dimensions, setting the chain groups
361
in all other dimensions to zero.
362
363
Definitely implement the following:
364
365
- ``base_ring`` - commutative ring (optional, default ZZ)
366
- ``cochain`` - a bool: whether to return the cochain complex
367
368
EXAMPLES::
369
370
sage: from sage.homology.cell_complex import GenericCellComplex
371
sage: A = GenericCellComplex()
372
sage: A.chain_complex()
373
Traceback (most recent call last):
374
...
375
NotImplementedError
376
"""
377
raise NotImplementedError
378
379
def homology(self, dim=None, **kwds):
380
r"""
381
The reduced homology of this cell complex.
382
383
:param dim: If None, then return the homology in every
384
dimension. If ``dim`` is an integer or list, return the
385
homology in the given dimensions. (Actually, if ``dim`` is
386
a list, return the homology in the range from ``min(dim)``
387
to ``max(dim)``.)
388
:type dim: integer or list of integers or None; optional,
389
default None
390
:param base_ring: commutative ring, must be ZZ or a field.
391
:type base_ring: optional, default ZZ
392
:param subcomplex: a subcomplex of this simplicial complex.
393
Compute homology relative to this subcomplex.
394
:type subcomplex: optional, default empty
395
:param generators: If True, return generators for the homology
396
groups along with the groups. NOTE: this is only implemented
397
if the CHomP package is available.
398
:type generators: boolean; optional, default False
399
:param cohomology: If True, compute cohomology rather than homology.
400
:type cohomology: boolean; optional, default False
401
:param algorithm: The options are 'auto', 'dhsw', 'pari' or 'no_chomp'.
402
See below for a description of what they mean.
403
:type algorithm: string; optional, default 'auto'
404
:param verbose: If True, print some messages as the homology is
405
computed.
406
:type verbose: boolean; optional, default False
407
408
.. note::
409
410
The keyword arguments to this function get passed on to
411
:meth:``chain_complex`` and its homology.
412
413
ALGORITHM:
414
415
If ``algorithm`` is set to 'auto' (the default), then use
416
CHomP if available. (CHomP is available at the web page
417
http://chomp.rutgers.edu/. It is also an experimental package
418
for Sage.)
419
420
CHomP computes homology, not cohomology, and only works over
421
the integers or finite prime fields. Therefore if any of
422
these conditions fails, or if CHomP is not present, or if
423
``algorithm`` is set to 'no_chomp', go to plan B: if ``self``
424
has a ``_homology`` method -- each simplicial complex has
425
this, for example -- then call that. Such a method implements
426
specialized algorithms for the particular type of cell
427
complex.
428
429
Otherwise, move on to plan C: compute the chain complex of
430
``self`` and compute its homology groups. To do this: over a
431
field, just compute ranks and nullities, thus obtaining
432
dimensions of the homology groups as vector spaces. Over the
433
integers, compute Smith normal form of the boundary matrices
434
defining the chain complex according to the value of
435
``algorithm``. If ``algorithm`` is 'auto' or 'no_chomp', then
436
for each relatively small matrix, use the standard Sage
437
method, which calls the Pari package. For any large matrix,
438
reduce it using the Dumas, Heckenbach, Saunders, and Welker
439
elimination algorithm: see
440
:func:`sage.homology.chain_complex.dhsw_snf` for details.
441
442
Finally, ``algorithm`` may also be 'pari' or 'dhsw', which
443
forces the named algorithm to be used regardless of the size
444
of the matrices and regardless of whether CHomP is available.
445
446
As of this writing, CHomP is by far the fastest option,
447
followed by the 'auto' or 'no_chomp' setting of using the
448
Dumas, Heckenbach, Saunders, and Welker elimination algorithm
449
for large matrices and Pari for small ones.
450
451
EXAMPLES::
452
453
sage: P = delta_complexes.RealProjectivePlane()
454
sage: P.homology()
455
{0: 0, 1: C2, 2: 0}
456
sage: P.homology(base_ring=GF(2))
457
{0: Vector space of dimension 0 over Finite Field of size 2,
458
1: Vector space of dimension 1 over Finite Field of size 2,
459
2: Vector space of dimension 1 over Finite Field of size 2}
460
sage: S7 = delta_complexes.Sphere(7)
461
sage: S7.homology(7)
462
Z
463
sage: cubical_complexes.KleinBottle().homology(1, base_ring=GF(2))
464
Vector space of dimension 2 over Finite Field of size 2
465
466
If CHomP is installed, Sage can compute generators of homology
467
groups::
468
469
sage: S2 = simplicial_complexes.Sphere(2)
470
sage: S2.homology(dim=2, generators=True, base_ring=GF(2)) # optional - CHomP
471
(Vector space of dimension 1 over Finite Field of size 2, [(0, 1, 2) + (0, 1, 3) + (0, 2, 3) + (1, 2, 3)])
472
473
When generators are computed, Sage returns a pair for each
474
dimension: the group and the list of generators. For
475
simplicial complexes, each generator is represented as a
476
linear combination of simplices, as above, and for cubical
477
complexes, each generator is a linear combination of cubes::
478
479
sage: S2_cub = cubical_complexes.Sphere(2)
480
sage: S2_cub.homology(dim=2, generators=True) # optional - CHomP
481
(Z, [-[[0,1] x [0,1] x [0,0]] + [[0,1] x [0,1] x [1,1]] - [[0,0] x [0,1] x [0,1]] - [[0,1] x [1,1] x [0,1]] + [[0,1] x [0,0] x [0,1]] + [[1,1] x [0,1] x [0,1]]])
482
"""
483
from sage.interfaces.chomp import have_chomp, homcubes, homsimpl
484
from sage.homology.cubical_complex import CubicalComplex
485
from sage.homology.simplicial_complex import SimplicialComplex
486
from sage.modules.all import VectorSpace
487
from sage.homology.chain_complex import HomologyGroup
488
489
base_ring = kwds.get('base_ring', ZZ)
490
cohomology = kwds.get('cohomology', False)
491
subcomplex = kwds.get('subcomplex', None)
492
verbose = kwds.get('verbose', False)
493
algorithm = kwds.get('algorithm', 'auto')
494
495
if dim is not None:
496
if isinstance(dim, (list, tuple)):
497
low = min(dim) - 1
498
high = max(dim) + 2
499
else:
500
low = dim - 1
501
high = dim + 2
502
dims = range(low, high)
503
else:
504
dims = None
505
506
# try to use CHomP if computing homology (not cohomology) and
507
# working over Z or F_p, p a prime.
508
if (algorithm == 'auto' and cohomology is False
509
and (base_ring == ZZ or (base_ring.is_prime_field()
510
and base_ring != QQ))):
511
# homcubes, homsimpl seems fastest if all of homology is computed.
512
H = None
513
if isinstance(self, CubicalComplex):
514
if have_chomp('homcubes'):
515
if 'subcomplex' in kwds:
516
del kwds['subcomplex']
517
H = homcubes(self, subcomplex, **kwds)
518
elif isinstance(self, SimplicialComplex):
519
if have_chomp('homsimpl'):
520
if 'subcomplex' in kwds:
521
del kwds['subcomplex']
522
H = homsimpl(self, subcomplex, **kwds)
523
# now pick off the requested dimensions
524
if H:
525
answer = {}
526
if not dims:
527
for d in range(self.dimension() + 1):
528
if base_ring == ZZ:
529
answer[d] = H.get(d, HomologyGroup(0))
530
else:
531
answer[d] = H.get(d, VectorSpace(base_ring, 0))
532
else:
533
for d in dims:
534
if base_ring == ZZ:
535
answer[d] = H.get(d, HomologyGroup(0))
536
else:
537
answer[d] = H.get(d, VectorSpace(base_ring, 0))
538
if dim is not None:
539
if not isinstance(dim, (list, tuple)):
540
if base_ring == ZZ:
541
answer = answer.get(dim, HomologyGroup(0))
542
else:
543
answer = answer.get(dim, VectorSpace(base_ring, 0))
544
return answer
545
546
# Derived classes can implement specialized algorithms using a
547
# _homology_ method. See SimplicialComplex for one example.
548
if hasattr(self, '_homology_'):
549
return self._homology_(dim, **kwds)
550
551
C = self.chain_complex(cochain=cohomology, augmented=True,
552
dimensions=dims, **kwds)
553
if 'subcomplex' in kwds:
554
del kwds['subcomplex']
555
answer = C.homology(**kwds)
556
if isinstance(answer, dict):
557
if cohomology:
558
too_big = self.dimension() + 1
559
if (not ((isinstance(dim, (list, tuple)) and too_big in dim)
560
or too_big == dim)
561
and too_big in answer):
562
del answer[too_big]
563
if -2 in answer:
564
del answer[-2]
565
if -1 in answer:
566
del answer[-1]
567
for d in range(self.dimension() + 1):
568
if d not in answer:
569
if base_ring == ZZ:
570
answer[d] = HomologyGroup(0)
571
else:
572
answer[d] = VectorSpace(base_ring, 0)
573
574
if dim is not None:
575
if isinstance(dim, (list, tuple)):
576
temp = {}
577
for n in dim:
578
temp[n] = answer[n]
579
answer = temp
580
else: # just a single dimension
581
if base_ring == ZZ:
582
answer = answer.get(dim, HomologyGroup(0))
583
else:
584
answer = answer.get(dim, VectorSpace(base_ring, 0))
585
return answer
586
587
def cohomology(self, dim=None, **kwds):
588
r"""
589
The reduced cohomology of this cell complex.
590
591
The arguments are the same as for the :meth:`homology` method,
592
except that :meth:`homology` accepts a ``cohomology`` key
593
word, while this function does not: ``cohomology`` is
594
automatically true here. Indeed, this function just calls
595
:meth:`homology` with ``cohomology`` set to True.
596
597
:param dim:
598
:param base_ring:
599
:param subcomplex:
600
:param algorithm:
601
:param verbose:
602
603
EXAMPLES::
604
605
sage: circle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]])
606
sage: circle.cohomology(0)
607
0
608
sage: circle.cohomology(1)
609
Z
610
sage: P2 = SimplicialComplex(5, [[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]]) # projective plane
611
sage: P2.cohomology(2)
612
C2
613
sage: P2.cohomology(2, base_ring=GF(2))
614
Vector space of dimension 1 over Finite Field of size 2
615
sage: P2.cohomology(2, base_ring=GF(3))
616
Vector space of dimension 0 over Finite Field of size 3
617
618
sage: cubical_complexes.KleinBottle().cohomology(2)
619
C2
620
621
Relative cohomology::
622
623
sage: T = SimplicialComplex(1, [[0,1]])
624
sage: U = SimplicialComplex(1, [[0], [1]])
625
sage: T.cohomology(1, subcomplex=U)
626
Z
627
628
A `\Delta`-complex example::
629
630
sage: s5 = delta_complexes.Sphere(5)
631
sage: s5.cohomology(base_ring=GF(7))[5]
632
Vector space of dimension 1 over Finite Field of size 7
633
"""
634
return self.homology(dim=dim, cohomology=True, **kwds)
635
636
def betti(self, dim=None, subcomplex=None):
637
r"""
638
The Betti numbers of this simplicial complex as a dictionary
639
(or a single Betti number, if only one dimension is given):
640
the ith Betti number is the rank of the ith homology group.
641
642
:param dim: If None, then return every Betti number, as
643
a dictionary with keys the non-negative integers. If
644
``dim`` is an integer or list, return the Betti number for
645
each given dimension. (Actually, if ``dim`` is a list,
646
return the Betti numbers, as a dictionary, in the range
647
from ``min(dim)`` to ``max(dim)``. If ``dim`` is a number,
648
return the Betti number in that dimension.)
649
:type dim: integer or list of integers or None; optional,
650
default None
651
:param subcomplex: a subcomplex of this cell complex. Compute
652
the Betti numbers of the homology relative to this
653
subcomplex.
654
:type subcomplex: optional, default None
655
656
EXAMPLES: Build the two-sphere as a three-fold join of a
657
two-point space with itself::
658
659
sage: S = SimplicialComplex(1, [[0], [1]])
660
sage: (S*S*S).betti()
661
{0: 1, 1: 0, 2: 1}
662
sage: (S*S*S).betti([1,2])
663
{1: 0, 2: 1}
664
sage: (S*S*S).betti(2)
665
1
666
667
Or build the two-sphere as a `\Delta`-complex::
668
669
sage: S2 = delta_complexes.Sphere(2)
670
sage: S2.betti([1,2])
671
{1: 0, 2: 1}
672
673
Or as a cubical complex::
674
675
sage: S2c = cubical_complexes.Sphere(2)
676
sage: S2c.betti(2)
677
1
678
"""
679
dict = {}
680
H = self.homology(dim, base_ring=QQ, subcomplex=subcomplex)
681
try:
682
for n in H.keys():
683
dict[n] = H[n].dimension()
684
if n == 0:
685
dict[n] += 1
686
return dict
687
except AttributeError:
688
return H.dimension()
689
690
############################################################
691
# end of chain complexes, homology
692
############################################################
693
694
def face_poset(self):
695
r"""
696
The face poset of this cell complex, the poset of
697
nonempty cells, ordered by inclusion.
698
699
This uses the :meth:`cells` method, and also assumes that for
700
each cell ``f``, all of ``f.faces()``, ``tuple(f)``, and
701
``f.dimension()`` make sense. (If this is not the case in
702
some derived class, as happens with `\Delta`-complexes, then
703
override this method.)
704
705
EXAMPLES::
706
707
sage: P = SimplicialComplex(3, [[0, 1], [1,2], [2,3]]).face_poset(); P
708
Finite poset containing 7 elements
709
sage: P.list()
710
[(3,), (2,), (2, 3), (1,), (0,), (0, 1), (1, 2)]
711
712
sage: S2 = cubical_complexes.Sphere(2)
713
sage: S2.face_poset()
714
Finite poset containing 26 elements
715
"""
716
from sage.combinat.posets.posets import Poset
717
from sage.misc.flatten import flatten
718
covers = {}
719
# The code for posets seems to work better if each cell is
720
# converted to a tuple.
721
all_cells = flatten([list(f) for f in self.cells().values()])
722
723
for C in all_cells:
724
if C.dimension() >= 0:
725
covers[tuple(C)] = []
726
for C in all_cells:
727
for face in C.faces():
728
if face.dimension() >= 0:
729
covers[tuple(face)].append(tuple(C))
730
return Poset(covers)
731
732
def graph(self):
733
"""
734
The 1-skeleton of this cell complex, as a graph.
735
736
This is not implemented for general cell complexes.
737
738
EXAMPLES::
739
740
sage: from sage.homology.cell_complex import GenericCellComplex
741
sage: A = GenericCellComplex()
742
sage: A.graph()
743
Traceback (most recent call last):
744
...
745
NotImplementedError
746
"""
747
raise NotImplementedError
748
749
def n_skeleton(self, n):
750
"""
751
The `n`-skeleton of this cell complex: the cell
752
complex obtained by discarding all of the simplices in
753
dimensions larger than `n`.
754
755
:param n: non-negative integer
756
757
This is not implemented for general cell complexes.
758
759
EXAMPLES::
760
761
sage: from sage.homology.cell_complex import GenericCellComplex
762
sage: A = GenericCellComplex()
763
sage: A.n_skeleton(3)
764
Traceback (most recent call last):
765
...
766
NotImplementedError
767
"""
768
raise NotImplementedError
769
770
def category(self):
771
"""
772
Return the category to which this chain complex belongs: the
773
category of all cell complexes.
774
775
This is not implemented for general cell complexes.
776
777
EXAMPLES::
778
779
sage: from sage.homology.cell_complex import GenericCellComplex
780
sage: A = GenericCellComplex()
781
sage: A.category()
782
Traceback (most recent call last):
783
...
784
NotImplementedError
785
"""
786
raise NotImplementedError
787
788
def _string_constants(self):
789
"""
790
Tuple containing the name of the type of complex, and the
791
singular and plural of the name of the cells from which it is
792
built. This is used in constructing the string representation.
793
794
:return: tuple of strings
795
796
This returns ``('Cell', 'cell', 'cells')``, as in "Cell
797
complex", "1 cell", and "24 cells", but in other classes it
798
could be overridden, as for example with ``('Cubical', 'cube',
799
'cubes')`` or ``('Delta', 'simplex', 'simplices')``. If for a
800
derived class, the basic form of the print representation is
801
acceptable, you can just modify these strings.
802
803
EXAMPLES::
804
805
sage: from sage.homology.cell_complex import GenericCellComplex
806
sage: GenericCellComplex()._string_constants()
807
('Cell', 'cell', 'cells')
808
sage: delta_complexes.Sphere(0)._string_constants()
809
('Delta', 'simplex', 'simplices')
810
sage: cubical_complexes.Sphere(0)._string_constants()
811
('Cubical', 'cube', 'cubes')
812
"""
813
return ('Cell', 'cell', 'cells')
814
815
def _repr_(self):
816
"""
817
Print representation.
818
819
:return: string
820
821
EXAMPLES::
822
823
sage: delta_complexes.Sphere(7) # indirect doctest
824
Delta complex with 8 vertices and 257 simplices
825
sage: delta_complexes.Torus()._repr_()
826
'Delta complex with 1 vertex and 7 simplices'
827
"""
828
vertices = len(self.n_cells(0))
829
Name, cell_name, cells_name = self._string_constants()
830
if vertices != 1:
831
vertex_string = "with %s vertices" % vertices
832
else:
833
vertex_string = "with 1 vertex"
834
cells = 0
835
for dim in self.cells():
836
cells += len(self.cells()[dim])
837
if cells != 1:
838
cells_string = " and %s %s" % (cells, cells_name)
839
else:
840
cells_string = " and 1 %s" % cell_name
841
return Name + " complex " + vertex_string + cells_string
842
843