Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/abstract_tree.py
8817 views
1
# -*- coding: utf-8 -*-
2
r"""
3
Abstract Recursive Trees
4
5
The purpose of this class is to help implement trees with a specific structure
6
on the children of each node. For instance, one could want to define a tree in
7
which each node sees its children as linearly (see the :mod:`Ordered Trees
8
<sage.combinat.ordered_tree>` module) or cyclically ordered.
9
10
**Tree structures**
11
12
Conceptually, one can define a tree structure from any object that can contain
13
others. Indeed, a list can contain lists which contain lists which contain
14
lists, and thus define a tree ... The same can be done with sets, or any kind
15
of iterable objects.
16
17
While any iterable is sufficient to encode trees, it can prove useful to have
18
other methods available like isomorphism tests (see next section), conversions
19
to DiGraphs objects (see :meth:`~.AbstractLabelledTree.as_digraph`) or
20
computation of the number of automorphisms constrained by the structure on
21
children. Providing such methods is the whole purpose of the
22
:class:`AbstractTree` class.
23
24
As a result, the :class:`AbstractTree` class is not meant to be
25
instantiated, but extended. It is expected that classes extending this one may
26
also inherit from classes representing iterables, for instance
27
:class:`ClonableArray` or :class:`~sage.structure.list_clone.ClonableList`
28
29
**Constrained Trees**
30
31
The tree built from a specific container will reflect the properties of the
32
container. Indeed, if ``A`` is an iterable class whose elements are linearly
33
ordered, a class ``B`` extending both of :class:`AbstractTree` and ``A`` will
34
be such that the children of a node will be linearly ordered. If ``A`` behaves
35
like a set (i.e. if there is no order on the elements it contains), then two
36
trees will be considered as equal if one can be obtained from the other
37
through permutations between the children of a same node (see next section).
38
39
**Paths and ID**
40
41
It is expected that each element of a set of children should be identified by
42
its index in the container. This way, any node of the tree can be identified
43
by a word describing a path from the root node.
44
45
**Canonical labellings**
46
47
Equality between instances of classes extending both :class:`AbstractTree`
48
and ``A`` is entirely defined by the equality defined on the elements of
49
``A``. A canonical labelling of such a tree, however, should be such that
50
two trees ``a`` and ``b`` satisfying ``a == b`` have the same canonical
51
labellings. On the other hand, the canonical labellings of trees ``a`` and
52
``b`` satisfying ``a != b`` are expected to be different.
53
54
For this reason, the values returned by the :meth:`canonical_labelling
55
<AbstractTree.canonical_labelling>` method heavily
56
depend on the data structure used for a node's children and **should be**
57
**overridden** by most of the classes extending :class:`AbstractTree` if it is
58
incoherent with the data structure.
59
60
**Authors**
61
62
- Florent Hivert (2010-2011): initial revision
63
- Frédéric Chapoton (2011): contributed some methods
64
"""
65
66
from sage.structure.list_clone import ClonableArray
67
from sage.rings.integer import Integer
68
from sage.misc.misc_c import prod
69
70
71
# Unfortunately Cython forbids multiple inheritance. Therefore, we do not
72
# inherit from SageObject to be able to inherit from Element or a subclass
73
# of it later.
74
class AbstractTree(object):
75
"""
76
Abstract Tree.
77
78
There is no data structure defined here, as this class is meant to be
79
extended, not instantiated.
80
81
.. rubric:: How should this class be extended?
82
83
A class extending :class:`AbstractTree
84
<sage.combinat.abstract_tree.AbstractTree>` should respect several
85
assumptions:
86
87
* For a tree ``T``, the call ``iter(T)`` should return an iterator on the
88
children of the root ``T``.
89
90
* The :meth:`canonical_labelling
91
<AbstractTree.canonical_labelling>` method
92
should return the same value for trees that are considered equal (see the
93
"canonical labellings" section in the documentation of the
94
:class:`AbstractTree <sage.combinat.abstract_tree.AbstractTree>` class).
95
96
* For a tree ``T`` the call ``T.parent().labelled_trees()`` should return
97
a parent for labelled trees of the same kind: for example,
98
99
- if ``T`` is a binary tree, ``T.parent()`` is ``BinaryTrees()`` and
100
``T.parent().labelled_trees()`` is ``LabelledBinaryTrees()``
101
102
- if ``T`` is an ordered tree, ``T.parent()`` is ``OrderedTrees()`` and
103
``T.parent().labelled_trees()`` is ``LabelledOrderedTrees()``
104
105
TESTS::
106
107
sage: TestSuite(OrderedTree()).run()
108
sage: TestSuite(BinaryTree()).run()
109
"""
110
def pre_order_traversal_iter(self):
111
r"""
112
The depth-first pre-order traversal iterator.
113
114
This method iters each node following the depth-first pre-order
115
traversal algorithm (recursive implementation). The algorithm
116
is::
117
118
yield the root (in the case of binary trees, if it is not
119
a leaf);
120
then explore each subtree (by the algorithm) from the
121
leftmost one to the rightmost one.
122
123
EXAMPLES:
124
125
For example, on the following binary tree `b`::
126
127
| ___3____ |
128
| / \ |
129
| 1 _7_ |
130
| \ / \ |
131
| 2 5 8 |
132
| / \ |
133
| 4 6 |
134
135
(only the nodes shown), the depth-first pre-order traversal
136
algorithm explores `b` in the following order of nodes:
137
`3,1,2,7,5,4,6,8`.
138
139
Another example::
140
141
| __1____ |
142
| / / / |
143
| 2 6 8_ |
144
| | | / / |
145
| 3_ 7 9 10 |
146
| / / |
147
| 4 5 |
148
149
The algorithm explores this labelled tree in the following
150
order: `1,2,3,4,5,6,7,8,9,10`.
151
152
TESTS::
153
154
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
155
sage: ascii_art([b])
156
[ ___3____ ]
157
[ / \ ]
158
[ 1 _7_ ]
159
[ \ / \ ]
160
[ 2 5 8 ]
161
[ / \ ]
162
[ 4 6 ]
163
sage: [n.label() for n in b.pre_order_traversal_iter()]
164
[3, 1, 2, 7, 5, 4, 6, 8]
165
166
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
167
sage: ascii_art([t])
168
[ __1____ ]
169
[ / / / ]
170
[ 2 6 8_ ]
171
[ | | / / ]
172
[ 3_ 7 9 10 ]
173
[ / / ]
174
[ 4 5 ]
175
sage: [n.label() for n in t.pre_order_traversal_iter()]
176
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
177
178
sage: [n for n in BinaryTree(None).pre_order_traversal_iter()]
179
[]
180
181
The following test checks that things do not go wrong if some among
182
the descendants of the tree are equal or even identical::
183
184
sage: u = BinaryTree(None)
185
sage: v = BinaryTree([u, u])
186
sage: w = BinaryTree([v, v])
187
sage: t = BinaryTree([w, w])
188
sage: t.node_number()
189
7
190
sage: l = [1 for i in t.pre_order_traversal_iter()]
191
sage: len(l)
192
7
193
"""
194
if self.is_empty():
195
return
196
yield self
197
# TODO:: PYTHON 3
198
# import itertools
199
# yield from itertools.chain(map(
200
# lambda c: c.pre_order_traversal_iter(),
201
# self
202
# ))
203
for children in self:
204
for node in children.pre_order_traversal_iter():
205
yield node
206
207
def iterative_pre_order_traversal(self, action=None):
208
r"""
209
Run the depth-first pre-order traversal algorithm (iterative
210
implementation) and subject every node encountered
211
to some procedure ``action``. The algorithm is::
212
213
manipulate the root with function `action` (in the case
214
of a binary tree, only if the root is not a leaf);
215
then explore each subtree (by the algorithm) from the
216
leftmost one to the rightmost one.
217
218
INPUT:
219
220
- ``action`` -- (optional) a function which takes a node as
221
input, and does something during the exploration
222
223
OUTPUT:
224
225
``None``. (This is *not* an iterator.)
226
227
.. SEEALSO::
228
229
- :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal_iter()`
230
- :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal()`
231
232
TESTS::
233
234
sage: l = []
235
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
236
sage: b
237
3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
238
sage: b.iterative_pre_order_traversal(lambda node: l.append(node.label()))
239
sage: l
240
[3, 1, 2, 7, 5, 4, 6, 8]
241
242
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
243
sage: t
244
1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
245
sage: l = []
246
sage: t.iterative_pre_order_traversal(lambda node: l.append(node.label()))
247
sage: l
248
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
249
sage: l = []
250
251
sage: BinaryTree().canonical_labelling().\
252
....: pre_order_traversal(lambda node: l.append(node.label()))
253
sage: l
254
[]
255
sage: OrderedTree([]).canonical_labelling().\
256
....: iterative_pre_order_traversal(lambda node: l.append(node.label()))
257
sage: l
258
[1]
259
260
The following test checks that things do not go wrong if some among
261
the descendants of the tree are equal or even identical::
262
263
sage: u = BinaryTree(None)
264
sage: v = BinaryTree([u, u])
265
sage: w = BinaryTree([v, v])
266
sage: t = BinaryTree([w, w])
267
sage: t.node_number()
268
7
269
sage: l = []
270
sage: t.iterative_pre_order_traversal(lambda node: l.append(1))
271
sage: len(l)
272
7
273
"""
274
if self.is_empty():
275
return
276
if action is None:
277
action = lambda x: None
278
stack = []
279
stack.append(self)
280
while len(stack) > 0:
281
node = stack.pop()
282
action(node)
283
for i in range(len(node)):
284
subtree = node[-i - 1]
285
if not subtree.is_empty():
286
stack.append(subtree)
287
288
def pre_order_traversal(self, action=None):
289
r"""
290
Run the depth-first pre-order traversal algorithm (recursive
291
implementation) and subject every node encountered
292
to some procedure ``action``. The algorithm is::
293
294
manipulate the root with function `action` (in the case
295
of a binary tree, only if the root is not a leaf);
296
then explore each subtree (by the algorithm) from the
297
leftmost one to the rightmost one.
298
299
INPUT:
300
301
- ``action`` -- (optional) a function which takes a node as
302
input, and does something during the exploration
303
304
OUTPUT:
305
306
``None``. (This is *not* an iterator.)
307
308
EXAMPLES:
309
310
For example, on the following binary tree `b`::
311
312
| ___3____ |
313
| / \ |
314
| 1 _7_ |
315
| \ / \ |
316
| 2 5 8 |
317
| / \ |
318
| 4 6 |
319
320
the depth-first pre-order traversal algorithm explores `b` in the
321
following order of nodes: `3,1,2,7,5,4,6,8`.
322
323
Another example::
324
325
| __1____ |
326
| / / / |
327
| 2 6 8_ |
328
| | | / / |
329
| 3_ 7 9 10 |
330
| / / |
331
| 4 5 |
332
333
The algorithm explores this tree in the following order:
334
`1,2,3,4,5,6,7,8,9,10`.
335
336
.. SEEALSO::
337
338
- :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal_iter()`
339
- :meth:`~sage.combinat.abstract_tree.AbstractTree.iterative_pre_order_traversal()`
340
341
TESTS::
342
343
sage: l = []
344
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
345
sage: b
346
3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
347
sage: b.pre_order_traversal(lambda node: l.append(node.label()))
348
sage: l
349
[3, 1, 2, 7, 5, 4, 6, 8]
350
sage: li = []
351
sage: b.iterative_pre_order_traversal(lambda node: li.append(node.label()))
352
sage: l == li
353
True
354
355
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
356
sage: t
357
1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
358
sage: l = []
359
sage: t.pre_order_traversal(lambda node: l.append(node.label()))
360
sage: l
361
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
362
sage: li = []
363
sage: t.iterative_pre_order_traversal(lambda node: li.append(node.label()))
364
sage: l == li
365
True
366
367
sage: l = []
368
sage: BinaryTree().canonical_labelling().\
369
....: pre_order_traversal(lambda node: l.append(node.label()))
370
sage: l
371
[]
372
sage: OrderedTree([]).canonical_labelling().\
373
....: pre_order_traversal(lambda node: l.append(node.label()))
374
sage: l
375
[1]
376
377
The following test checks that things do not go wrong if some among
378
the descendants of the tree are equal or even identical::
379
380
sage: u = BinaryTree(None)
381
sage: v = BinaryTree([u, u])
382
sage: w = BinaryTree([v, v])
383
sage: t = BinaryTree([w, w])
384
sage: t.node_number()
385
7
386
sage: l = []
387
sage: t.pre_order_traversal(lambda node: l.append(1))
388
sage: len(l)
389
7
390
"""
391
if action is None:
392
action = lambda x: None
393
for node in self.pre_order_traversal_iter():
394
action(node)
395
396
def post_order_traversal_iter(self):
397
r"""
398
The depth-first post-order traversal iterator.
399
400
This method iters each node following the depth-first post-order
401
traversal algorithm (recursive implementation). The algorithm
402
is::
403
404
explore each subtree (by the algorithm) from the
405
leftmost one to the rightmost one;
406
then yield the root (in the case of binary trees, only if
407
it is not a leaf).
408
409
EXAMPLES:
410
411
For example on the following binary tree `b`::
412
413
| ___3____ |
414
| / \ |
415
| 1 _7_ |
416
| \ / \ |
417
| 2 5 8 |
418
| / \ |
419
| 4 6 |
420
421
(only the nodes are shown), the depth-first post-order traversal
422
algorithm explores `b` in the following order of nodes:
423
`2,1,4,6,5,8,7,3`.
424
425
For another example, consider the labelled tree::
426
427
| __1____ |
428
| / / / |
429
| 2 6 8_ |
430
| | | / / |
431
| 3_ 7 9 10 |
432
| / / |
433
| 4 5 |
434
435
The algorithm explores this tree in the following order:
436
`4,5,3,2,7,6,9,10,8,1`.
437
438
TESTS::
439
440
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
441
sage: ascii_art([b])
442
[ ___3____ ]
443
[ / \ ]
444
[ 1 _7_ ]
445
[ \ / \ ]
446
[ 2 5 8 ]
447
[ / \ ]
448
[ 4 6 ]
449
sage: [node.label() for node in b.post_order_traversal_iter()]
450
[2, 1, 4, 6, 5, 8, 7, 3]
451
452
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
453
sage: ascii_art([t])
454
[ __1____ ]
455
[ / / / ]
456
[ 2 6 8_ ]
457
[ | | / / ]
458
[ 3_ 7 9 10 ]
459
[ / / ]
460
[ 4 5 ]
461
sage: [node.label() for node in t.post_order_traversal_iter()]
462
[4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
463
464
sage: [node.label() for node in BinaryTree().canonical_labelling().\
465
....: post_order_traversal_iter()]
466
[]
467
sage: [node.label() for node in OrderedTree([]).\
468
....: canonical_labelling().post_order_traversal_iter()]
469
[1]
470
471
The following test checks that things do not go wrong if some among
472
the descendants of the tree are equal or even identical::
473
474
sage: u = BinaryTree(None)
475
sage: v = BinaryTree([u, u])
476
sage: w = BinaryTree([v, v])
477
sage: t = BinaryTree([w, w])
478
sage: t.node_number()
479
7
480
sage: l = [1 for i in t.post_order_traversal_iter()]
481
sage: len(l)
482
7
483
"""
484
if self.is_empty():
485
return
486
# TODO:: PYTHON 3
487
# import itertools
488
# yield from itertools.chain(map(
489
# lambda c: c.post_order_traversal_iter(),
490
# self
491
# ))
492
for children in self:
493
for node in children.post_order_traversal_iter():
494
yield node
495
yield self
496
497
def post_order_traversal(self, action=None):
498
r"""
499
Run the depth-first post-order traversal algorithm (recursive
500
implementation) and subject every node encountered
501
to some procedure ``action``. The algorithm is::
502
503
explore each subtree (by the algorithm) from the
504
leftmost one to the rightmost one;
505
then manipulate the root with function `action` (in the
506
case of a binary tree, only if the root is not a leaf).
507
508
INPUT:
509
510
- ``action`` -- (optional) a function which takes a node as
511
input, and does something during the exploration
512
513
OUTPUT:
514
515
``None``. (This is *not* an iterator.)
516
517
.. SEEALSO::
518
519
- :meth:`~sage.combinat.abstract_tree.AbstractTree.post_order_traversal_iter()`
520
- :meth:`~sage.combinat.abstract_tree.AbstractTree.iterative_post_order_traversal()`
521
522
TESTS::
523
524
sage: l = []
525
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
526
sage: b
527
3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
528
sage: b.post_order_traversal(lambda node: l.append(node.label()))
529
sage: l
530
[2, 1, 4, 6, 5, 8, 7, 3]
531
532
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).\
533
....: canonical_labelling(); t
534
1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
535
sage: l = []
536
sage: t.post_order_traversal(lambda node: l.append(node.label()))
537
sage: l
538
[4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
539
540
sage: l = []
541
sage: BinaryTree().canonical_labelling().\
542
....: post_order_traversal(lambda node: l.append(node.label()))
543
sage: l
544
[]
545
sage: OrderedTree([]).canonical_labelling().\
546
....: post_order_traversal(lambda node: l.append(node.label()))
547
sage: l
548
[1]
549
550
The following test checks that things do not go wrong if some among
551
the descendants of the tree are equal or even identical::
552
553
sage: u = BinaryTree(None)
554
sage: v = BinaryTree([u, u])
555
sage: w = BinaryTree([v, v])
556
sage: t = BinaryTree([w, w])
557
sage: t.node_number()
558
7
559
sage: l = []
560
sage: t.post_order_traversal(lambda node: l.append(1))
561
sage: len(l)
562
7
563
"""
564
if action is None:
565
action = lambda x: None
566
for node in self.post_order_traversal_iter():
567
action(node)
568
569
def iterative_post_order_traversal(self, action=None):
570
r"""
571
Run the depth-first post-order traversal algorithm (iterative
572
implementation) and subject every node encountered
573
to some procedure ``action``. The algorithm is::
574
575
explore each subtree (by the algorithm) from the
576
leftmost one to the rightmost one;
577
then manipulate the root with function `action` (in the
578
case of a binary tree, only if the root is not a leaf).
579
580
INPUT:
581
582
- ``action`` -- (optional) a function which takes a node as
583
input, and does something during the exploration
584
585
OUTPUT:
586
587
``None``. (This is *not* an iterator.)
588
589
.. SEEALSO::
590
591
- :meth:`~sage.combinat.abstract_tree.AbstractTree.post_order_traversal_iter()`
592
593
TESTS::
594
595
sage: l = []
596
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
597
sage: b
598
3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
599
sage: b.iterative_post_order_traversal(lambda node: l.append(node.label()))
600
sage: l
601
[2, 1, 4, 6, 5, 8, 7, 3]
602
603
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
604
sage: t
605
1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
606
sage: l = []
607
sage: t.iterative_post_order_traversal(lambda node: l.append(node.label()))
608
sage: l
609
[4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
610
611
sage: l = []
612
sage: BinaryTree().canonical_labelling().\
613
....: iterative_post_order_traversal(
614
....: lambda node: l.append(node.label()))
615
sage: l
616
[]
617
sage: OrderedTree([]).canonical_labelling().\
618
....: iterative_post_order_traversal(
619
....: lambda node: l.append(node.label()))
620
sage: l
621
[1]
622
623
The following test checks that things do not go wrong if some among
624
the descendants of the tree are equal or even identical::
625
626
sage: u = BinaryTree(None)
627
sage: v = BinaryTree([u, u])
628
sage: w = BinaryTree([v, v])
629
sage: t = BinaryTree([w, w])
630
sage: t.node_number()
631
7
632
sage: l = []
633
sage: t.iterative_post_order_traversal(lambda node: l.append(1))
634
sage: len(l)
635
7
636
"""
637
if self.is_empty():
638
return
639
if action is None:
640
action = lambda x: None
641
stack = [self]
642
while len(stack) > 0:
643
node = stack[-1]
644
if node != None:
645
# A "None" on the stack means that the node right before
646
# it on the stack has already been "exploded" into
647
# subtrees, and should not be exploded again, but instead
648
# should be manipulated and removed from the stack.
649
stack.append(None)
650
for i in range(len(node)):
651
subtree = node[-i - 1]
652
if not subtree.is_empty():
653
stack.append(subtree)
654
else:
655
stack.pop()
656
node = stack.pop()
657
action(node)
658
659
def breadth_first_order_traversal(self, action=None):
660
r"""
661
Run the breadth-first post-order traversal algorithm
662
and subject every node encountered to some procedure
663
``action``. The algorithm is::
664
665
queue <- [ root ];
666
while the queue is not empty:
667
node <- pop( queue );
668
manipulate the node;
669
prepend to the queue the list of all subtrees of
670
the node (from the rightmost to the leftmost).
671
672
INPUT:
673
674
- ``action`` -- (optional) a function which takes a node as
675
input, and does something during the exploration
676
677
OUTPUT:
678
679
``None``. (This is *not* an iterator.)
680
681
EXAMPLES:
682
683
For example, on the following binary tree `b`::
684
685
| ___3____ |
686
| / \ |
687
| 1 _7_ |
688
| \ / \ |
689
| 2 5 8 |
690
| / \ |
691
| 4 6 |
692
693
the breadth-first order traversal algorithm explores `b` in the
694
following order of nodes: `3,1,7,2,5,8,4,6`.
695
696
TESTS::
697
698
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
699
sage: l = []
700
sage: b.breadth_first_order_traversal(lambda node: l.append(node.label()))
701
sage: l
702
[3, 1, 7, 2, 5, 8, 4, 6]
703
704
sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
705
sage: t
706
1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
707
sage: l = []
708
sage: t.breadth_first_order_traversal(lambda node: l.append(node.label()))
709
sage: l
710
[1, 2, 6, 8, 3, 7, 9, 10, 4, 5]
711
712
sage: l = []
713
sage: BinaryTree().canonical_labelling().\
714
....: breadth_first_order_traversal(
715
....: lambda node: l.append(node.label()))
716
sage: l
717
[]
718
sage: OrderedTree([]).canonical_labelling().\
719
....: breadth_first_order_traversal(
720
....: lambda node: l.append(node.label()))
721
sage: l
722
[1]
723
"""
724
if self.is_empty():
725
return
726
if action is None:
727
action = lambda x: None
728
queue = []
729
queue.append(self)
730
while len(queue) > 0:
731
node = queue.pop()
732
action(node)
733
for subtree in node:
734
if not subtree.is_empty():
735
queue.insert(0, subtree)
736
737
def subtrees(self):
738
"""
739
Return a generator for all nonempty subtrees of ``self``.
740
741
The number of nonempty subtrees of a tree is its number of
742
nodes. (The word "nonempty" makes a difference only in the
743
case of binary trees. For ordered trees, for example, all
744
trees are nonempty.)
745
746
EXAMPLES::
747
748
sage: list(OrderedTree([]).subtrees())
749
[[]]
750
sage: list(OrderedTree([[],[[]]]).subtrees())
751
[[[], [[]]], [], [[]], []]
752
753
sage: list(OrderedTree([[],[[]]]).canonical_labelling().subtrees())
754
[1[2[], 3[4[]]], 2[], 3[4[]], 4[]]
755
756
sage: list(BinaryTree([[],[[],[]]]).subtrees())
757
[[[., .], [[., .], [., .]]], [., .], [[., .], [., .]], [., .], [., .]]
758
759
sage: v = BinaryTree([[],[]])
760
sage: list(v.canonical_labelling().subtrees())
761
[2[1[., .], 3[., .]], 1[., .], 3[., .]]
762
763
TESTS::
764
765
sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
766
sage: t.node_number() == len(list(t.subtrees()))
767
True
768
sage: list(BinaryTree().subtrees())
769
[]
770
sage: bt = BinaryTree([[],[[],[]]])
771
sage: bt.node_number() == len(list(bt.subtrees()))
772
True
773
"""
774
return self.pre_order_traversal_iter()
775
776
def paths(self):
777
"""
778
Return a generator for all paths to nodes of ``self``.
779
780
OUTPUT:
781
782
This method returns a list of sequences of integers. Each of these
783
sequences represents a path from the root node to some node. For
784
instance, `(1, 3, 2, 5, 0, 3)` represents the node obtained by
785
choosing the 1st child of the root node (in the ordering returned
786
by ``iter``), then the 3rd child of its child, then the 2nd child
787
of the latter, etc. (where the labelling of the children is
788
zero-based).
789
790
The root element is represented by the empty tuple ``()``.
791
792
EXAMPLES::
793
794
sage: list(OrderedTree([]).paths())
795
[()]
796
sage: list(OrderedTree([[],[[]]]).paths())
797
[(), (0,), (1,), (1, 0)]
798
799
sage: list(BinaryTree([[],[[],[]]]).paths())
800
[(), (0,), (1,), (1, 0), (1, 1)]
801
802
TESTS::
803
804
sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
805
sage: t.node_number() == len(list(t.paths()))
806
True
807
sage: list(BinaryTree().paths())
808
[]
809
sage: bt = BinaryTree([[],[[],[]]])
810
sage: bt.node_number() == len(list(bt.paths()))
811
True
812
"""
813
if not self.is_empty():
814
yield ()
815
for i, t in enumerate(self):
816
for p in t.paths():
817
yield (i,)+p
818
819
def node_number(self):
820
"""
821
The number of nodes of ``self``.
822
823
EXAMPLES::
824
825
sage: OrderedTree().node_number()
826
1
827
sage: OrderedTree([]).node_number()
828
1
829
sage: OrderedTree([[],[]]).node_number()
830
3
831
sage: OrderedTree([[],[[]]]).node_number()
832
4
833
sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number()
834
13
835
836
EXAMPLES::
837
838
sage: BinaryTree(None).node_number()
839
0
840
sage: BinaryTree([]).node_number()
841
1
842
sage: BinaryTree([[], None]).node_number()
843
2
844
sage: BinaryTree([[None, [[], []]], None]).node_number()
845
5
846
"""
847
if self.is_empty():
848
return 0
849
else:
850
return sum((i.node_number() for i in self), Integer(1))
851
852
def depth(self):
853
"""
854
The depth of ``self``.
855
856
EXAMPLES::
857
858
sage: OrderedTree().depth()
859
1
860
sage: OrderedTree([]).depth()
861
1
862
sage: OrderedTree([[],[]]).depth()
863
2
864
sage: OrderedTree([[],[[]]]).depth()
865
3
866
sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).depth()
867
4
868
869
sage: BinaryTree().depth()
870
0
871
sage: BinaryTree([[],[[],[]]]).depth()
872
3
873
"""
874
if self:
875
return Integer(1 + max(i.depth() for i in self))
876
else:
877
return Integer(0 if self.is_empty() else 1)
878
879
def _ascii_art_(self):
880
r"""
881
TESTS::
882
883
sage: t = OrderedTree([])
884
sage: ascii_art(t)
885
o
886
sage: t = OrderedTree([[]])
887
sage: aa = ascii_art(t);aa
888
o
889
|
890
o
891
sage: aa.get_baseline()
892
2
893
sage: tt1 = OrderedTree([[],[[],[],[[[[]]]]],[[[],[],[],[]]]])
894
sage: ascii_art(tt1)
895
_____o_______
896
/ / /
897
o _o__ o
898
/ / / |
899
o o o __o___
900
| / / / /
901
o o o o o
902
|
903
o
904
|
905
o
906
sage: ascii_art(tt1.canonical_labelling())
907
______1_______
908
/ / /
909
2 _3__ 10
910
/ / / |
911
4 5 6 ___11____
912
| / / / /
913
7 12 13 14 15
914
|
915
8
916
|
917
9
918
sage: ascii_art(OrderedTree([[],[[]]]))
919
o_
920
/ /
921
o o
922
|
923
o
924
sage: t = OrderedTree([[[],[[[],[]]],[[]]],[[[[[],[]]]]],[[],[]]])
925
sage: ascii_art(t)
926
_____o_______
927
/ / /
928
__o____ o o_
929
/ / / | / /
930
o o o o o o
931
| | |
932
o_ o o
933
/ / |
934
o o o_
935
/ /
936
o o
937
sage: ascii_art(t.canonical_labelling())
938
______1________
939
/ / /
940
__2____ 10 16_
941
/ / / | / /
942
3 4 8 11 17 18
943
| | |
944
5_ 9 12
945
/ / |
946
6 7 13_
947
/ /
948
14 15
949
"""
950
node_to_str = lambda t: str(t.label()) if hasattr(t, "label") else "o"
951
952
if self.is_empty():
953
from sage.misc.ascii_art import empty_ascii_art
954
return empty_ascii_art
955
956
from sage.misc.ascii_art import AsciiArt
957
if len(self) == 0:
958
t_repr = AsciiArt( [node_to_str(self)] )
959
t_repr._root = 1
960
return t_repr
961
if len(self) == 1:
962
repr_child = self[0]._ascii_art_()
963
sep = AsciiArt( [" "*(repr_child._root-1)] )
964
t_repr = AsciiArt( [node_to_str(self)] )
965
t_repr._root = 1
966
repr_root = (sep + t_repr)*(sep + AsciiArt( ["|"] ))
967
t_repr = repr_root * repr_child
968
t_repr._root = repr_child._root
969
t_repr._baseline = t_repr._h - 1
970
return t_repr
971
# General case
972
l_repr = [subtree._ascii_art_() for subtree in self]
973
acc = l_repr.pop(0)
974
whitesep = acc._root+1
975
lf_sep = " "*(acc._root+1) + "_"*(acc._l-acc._root)
976
ls_sep = " "*(acc._root) + "/" + " "*(acc._l-acc._root)
977
while len(l_repr) > 0:
978
t_repr = l_repr.pop(0)
979
acc += AsciiArt([" "]) + t_repr
980
if len(l_repr) == 0: lf_sep += "_"*(t_repr._root+1)
981
else: lf_sep += "_"*(t_repr._l+1)
982
ls_sep += " "*(t_repr._root) + "/" + " "*(t_repr._l-t_repr._root)
983
mid = whitesep + int((len(lf_sep)-whitesep)/2)
984
node = node_to_str( self )
985
t_repr = AsciiArt([lf_sep[:mid-1] + node + lf_sep[mid+len(node)-1:], ls_sep]) * acc
986
t_repr._root = mid
987
t_repr._baseline = t_repr._h - 1
988
return t_repr
989
990
def canonical_labelling(self,shift=1):
991
"""
992
Returns a labelled version of ``self``.
993
994
The actual canonical labelling is currently unspecified. However, it
995
is guaranteed to have labels in `1...n` where `n` is the number of
996
nodes of the tree. Moreover, two (unlabelled) trees compare as equal if
997
and only if their canonical labelled trees compare as equal.
998
999
EXAMPLES::
1000
1001
sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
1002
sage: t.canonical_labelling()
1003
1[2[], 3[4[], 5[6[], 7[]], 8[9[], 10[]]], 11[12[], 13[]]]
1004
1005
sage: BinaryTree([]).canonical_labelling()
1006
1[., .]
1007
sage: BinaryTree([[],[[],[]]]).canonical_labelling()
1008
2[1[., .], 4[3[., .], 5[., .]]]
1009
1010
TESTS::
1011
1012
sage: BinaryTree().canonical_labelling()
1013
.
1014
"""
1015
LTR = self.parent().labelled_trees()
1016
liste = []
1017
deca = 1
1018
for subtree in self:
1019
liste += [subtree.canonical_labelling(shift+deca)]
1020
deca += subtree.node_number()
1021
return LTR._element_constructor_(liste,label=shift)
1022
1023
def to_hexacode(self):
1024
r"""
1025
Transform a tree into an hexadecimal string.
1026
1027
The definition of the hexacode is recursive. The first letter is
1028
the valence of the root as an hexadecimal (up to 15), followed by
1029
the concatenation of the hexacodes of the subtrees.
1030
1031
This method only works for trees where every vertex has
1032
valency at most 15.
1033
1034
See :func:`from_hexacode` for the reverse transformation.
1035
1036
EXAMPLES::
1037
1038
sage: from sage.combinat.abstract_tree import from_hexacode
1039
sage: LT = LabelledOrderedTrees()
1040
sage: from_hexacode('2010', LT).to_hexacode()
1041
'2010'
1042
sage: LT.an_element().to_hexacode()
1043
'3020010'
1044
sage: t = from_hexacode('a0000000000000000', LT)
1045
sage: t.to_hexacode()
1046
'a0000000000'
1047
1048
sage: OrderedTrees(6).an_element().to_hexacode()
1049
'500000'
1050
1051
TESTS::
1052
1053
sage: one = LT([], label='@')
1054
sage: LT([one for _ in range(15)], label='@').to_hexacode()
1055
'f000000000000000'
1056
sage: LT([one for _ in range(16)], label='@').to_hexacode()
1057
Traceback (most recent call last):
1058
...
1059
ValueError: the width of the tree is too large
1060
"""
1061
if len(self) > 15:
1062
raise ValueError("the width of the tree is too large")
1063
if self.node_number() == 1:
1064
return "0"
1065
return "".join(["%x" % len(self)] + [u.to_hexacode() for u in self])
1066
1067
def tree_factorial(self):
1068
"""
1069
Return the tree-factorial of ``self``.
1070
1071
Definition:
1072
1073
The tree-factorial `T!` of a tree `T` is the product `\prod_{v\in
1074
T}\#\mbox{children}(v)`.
1075
1076
EXAMPLES::
1077
1078
sage: LT = LabelledOrderedTrees()
1079
sage: t = LT([LT([],label=6),LT([],label=1)],label=9)
1080
sage: t.tree_factorial()
1081
3
1082
1083
sage: BinaryTree([[],[[],[]]]).tree_factorial()
1084
15
1085
1086
TESTS::
1087
1088
sage: BinaryTree().tree_factorial()
1089
1
1090
"""
1091
nb = self.node_number()
1092
if nb <= 1:
1093
return 1
1094
return nb * prod(s.tree_factorial() for s in self)
1095
1096
def _latex_(self):
1097
r"""
1098
Generate `\LaTeX` output which can be easily modified.
1099
1100
TESTS::
1101
1102
sage: latex(BinaryTree([[[],[]],[[],None]]))
1103
{ \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1104
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$$}
1105
;}\newcommand{\nodec}{\node[draw,circle] (c) {$$}
1106
;}\newcommand{\noded}{\node[draw,circle] (d) {$$}
1107
;}\newcommand{\nodee}{\node[draw,circle] (e) {$$}
1108
;}\newcommand{\nodef}{\node[draw,circle] (f) {$$}
1109
;}\begin{tikzpicture}[auto]
1110
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1111
\& \& \& \nodea \& \& \& \\
1112
\& \nodeb \& \& \& \& \nodee \& \\
1113
\nodec \& \& \noded \& \& \nodef \& \& \\
1114
};
1115
<BLANKLINE>
1116
\path[ultra thick, red] (b) edge (c) edge (d)
1117
(e) edge (f)
1118
(a) edge (b) edge (e);
1119
\end{tikzpicture}}
1120
"""
1121
###############################################################################
1122
# # use to load tikz in the preamble (one for *view* and one for *notebook*)
1123
from sage.misc.latex import latex
1124
latex.add_package_to_preamble_if_available("tikz")
1125
latex.add_to_mathjax_avoid_list("tikz")
1126
###############################################################################
1127
# latex environnement : TikZ
1128
begin_env = "\\begin{tikzpicture}[auto]\n"
1129
end_env = "\\end{tikzpicture}"
1130
# it uses matrix trick to place each node
1131
matrix_begin = "\\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{\n"
1132
matrix_end = "\\\\\n};\n"
1133
# a basic path to each edges
1134
path_begin = "\\path[ultra thick, red] "
1135
path_end = ";\n"
1136
# to make a pretty output, it creates one LaTeX command for
1137
# each node
1138
cmd = "\\node"
1139
new_cmd1 = "\\newcommand{" + cmd
1140
new_cmd2 = "}{\\node[draw,circle] ("
1141
new_cmd3 = ") {$"
1142
new_cmd4 = "$}\n;}"
1143
# some variables to simplify code
1144
sep = "\\&"
1145
space = " "*9
1146
sepspace = sep + space
1147
spacesep = space + sep
1148
node_to_str = lambda node: " " + node + " " * (len(space) - 1 - len(node))
1149
# # TODO:: modify how to create nodes --> new_cmd : \\node[...] in create_node
1150
num = [0]
1151
1152
def resolve(self):
1153
nodes = []; matrix = []; edges = []
1154
1155
def create_node(self):
1156
r"""
1157
create a name (infixe reading)
1158
-> ex: b
1159
create a new command:
1160
-> ex: \newcommand{\nodeb}{\node[draw,circle] (b) {$$};
1161
return the name and the command to build:
1162
. the matrix
1163
. and the edges
1164
"""
1165
name = reduce(
1166
lambda x, y: x + y,
1167
map(
1168
lambda x: chr(ord(x) + 49),
1169
list(str(num[0]))),
1170
"")
1171
node = cmd + name
1172
nodes.append((name,
1173
(str(self.label()) if hasattr(self, "label") else ""))
1174
)
1175
num[0] += 1
1176
return node, name
1177
1178
def empty_tree():
1179
r"""
1180
TESTS::
1181
1182
sage: t = BinaryTree()
1183
sage: print latex(t)
1184
{ \begin{tikzpicture}[auto]
1185
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1186
\\
1187
};
1188
\end{tikzpicture}}
1189
"""
1190
matrix.append(space)
1191
1192
def one_node_tree(self):
1193
r"""
1194
TESTS::
1195
1196
sage: t = BinaryTree([]); print latex(t)
1197
{ \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1198
;}\begin{tikzpicture}[auto]
1199
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1200
\nodea \\
1201
};
1202
\end{tikzpicture}}
1203
sage: t = OrderedTree([]); print latex(t)
1204
{ \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1205
;}\begin{tikzpicture}[auto]
1206
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1207
\nodea \\
1208
};
1209
\end{tikzpicture}}
1210
"""
1211
node, _ = create_node(self)
1212
matrix.append(node_to_str(node))
1213
1214
def concat_matrix(mat, mat2):
1215
lmat = len(mat); lmat2 = len(mat2)
1216
for i in range(max(lmat, lmat2)):
1217
# mat[i] --> n & n & ...
1218
# mat2[i] -> n' & n' & ...
1219
# ==> n & n & ... & n' & n' & ...
1220
try:
1221
mat[i] += sep + mat2[i]
1222
except:
1223
if i >= lmat:
1224
if i != 0:
1225
# mat[i] does not exist but
1226
# mat[0] has k "&"
1227
# mat2[i] -> n' & n' & ...
1228
# ==> (_ &)*k+1 n' & n' & ...
1229
nb_of_and = mat[0].count(sep) - mat2[0].count(sep)
1230
mat.append(spacesep * (nb_of_and) + mat2[i])
1231
else:
1232
# mat is empty
1233
# mat2[i] -> n' & n' & ...
1234
# ==> mat2
1235
mat.extend(mat2)
1236
return
1237
else:
1238
# mat[i] -> n & n & ...
1239
# mat2[i] does not exist but mat2[0] exists
1240
# # and has k "&"
1241
# NOTE:: i != 0 because that is a no-empty subtree.
1242
# ==> n & n & ... (& _)*k+1
1243
nb_of_and = mat2[0].count(sep)
1244
mat[i] += sepspace * (nb_of_and + 1)
1245
1246
def tmp(subtree, edge, nodes, edges, matrix):
1247
if not subtree.is_empty():
1248
# # create representation of the subtree
1249
nodes_st, matrix_st, edges_st = resolve(subtree)
1250
# # add its nodes to the "global" nodes set
1251
nodes.extend(nodes_st)
1252
# # create a new edge between the root and the subtree
1253
edge.append(nodes_st[0][0])
1254
# # add the subtree edges to the "global" edges set
1255
edges.extend(edges_st)
1256
# # build a new matrix by concatenation
1257
concat_matrix(matrix, matrix_st)
1258
else:
1259
concat_matrix(matrix, [space])
1260
1261
def pair_nodes_tree(self, nodes, edges, matrix):
1262
r"""
1263
TESTS::
1264
1265
sage: t = OrderedTree([[[],[]],[[],[]]]).\
1266
....: canonical_labelling(); print latex(t)
1267
{ \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1268
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1269
;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1270
;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1271
;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1272
;}\newcommand{\nodef}{\node[draw,circle] (f) {$6$}
1273
;}\newcommand{\nodeg}{\node[draw,circle] (g) {$7$}
1274
;}\begin{tikzpicture}[auto]
1275
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1276
\& \& \& \nodea \& \& \& \\
1277
\& \nodeb \& \& \& \& \nodee \& \\
1278
\nodec \& \& \noded \& \& \nodef \& \& \nodeg \\
1279
};
1280
<BLANKLINE>
1281
\path[ultra thick, red] (b) edge (c) edge (d)
1282
(e) edge (f) edge (g)
1283
(a) edge (b) edge (e);
1284
\end{tikzpicture}}
1285
sage: t = BinaryTree([[],[[],[]]]); print latex(t)
1286
{ \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1287
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$$}
1288
;}\newcommand{\nodec}{\node[draw,circle] (c) {$$}
1289
;}\newcommand{\noded}{\node[draw,circle] (d) {$$}
1290
;}\newcommand{\nodee}{\node[draw,circle] (e) {$$}
1291
;}\begin{tikzpicture}[auto]
1292
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1293
\& \nodea \& \& \& \\
1294
\nodeb \& \& \& \nodec \& \\
1295
\& \& \noded \& \& \nodee \\
1296
};
1297
<BLANKLINE>
1298
\path[ultra thick, red] (c) edge (d) edge (e)
1299
(a) edge (b) edge (c);
1300
\end{tikzpicture}}
1301
"""
1302
# build all subtree matrices.
1303
node, name = create_node(self)
1304
edge = [name]
1305
split = int(len(self) / 2)
1306
# the left part
1307
for i in range(split):
1308
tmp(self[i], edge, nodes, edges, matrix)
1309
# # prepare the root line
1310
nb_of_and = matrix[0].count(sep)
1311
# the middle
1312
for i in range(len(matrix)):
1313
matrix[i] += sepspace
1314
# the right part
1315
for i in range(split, len(self)):
1316
tmp(self[i], edge, nodes, edges, matrix)
1317
1318
# # create the root line
1319
root_line = (spacesep * (nb_of_and + 1) + node_to_str(node) +
1320
sepspace * (matrix[0].count(sep) - nb_of_and - 1))
1321
matrix.insert(0, root_line)
1322
# add edges from the root
1323
edges.append(edge)
1324
1325
def odd_nodes_tree(self, nodes, edges, matrix):
1326
r"""
1327
TESTS::
1328
1329
sage: t = OrderedTree([[]]).canonical_labelling()
1330
sage: print latex(t)
1331
{ \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1332
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1333
;}\begin{tikzpicture}[auto]
1334
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1335
\nodea \\
1336
\nodeb \\
1337
};
1338
<BLANKLINE>
1339
\path[ultra thick, red] (a) edge (b);
1340
\end{tikzpicture}}
1341
sage: t = OrderedTree([[[],[]]]).canonical_labelling(); print latex(t)
1342
{ \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1343
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1344
;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1345
;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1346
;}\begin{tikzpicture}[auto]
1347
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1348
\& \nodea \& \\
1349
\& \nodeb \& \\
1350
\nodec \& \& \noded \\
1351
};
1352
<BLANKLINE>
1353
\path[ultra thick, red] (b) edge (c) edge (d)
1354
(a) edge (b);
1355
\end{tikzpicture}}
1356
sage: t = OrderedTree([[[],[],[]]]).canonical_labelling(); print latex(t)
1357
{ \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1358
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1359
;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1360
;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1361
;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1362
;}\begin{tikzpicture}[auto]
1363
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1364
\& \nodea \& \\
1365
\& \nodeb \& \\
1366
\nodec \& \noded \& \nodee \\
1367
};
1368
<BLANKLINE>
1369
\path[ultra thick, red] (b) edge (c) edge (d) edge (e)
1370
(a) edge (b);
1371
\end{tikzpicture}}
1372
sage: t = OrderedTree([[[],[],[]],[],[]]).canonical_labelling(); print latex(t)
1373
{ \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1374
;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1375
;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1376
;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1377
;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1378
;}\newcommand{\nodef}{\node[draw,circle] (f) {$6$}
1379
;}\newcommand{\nodeg}{\node[draw,circle] (g) {$7$}
1380
;}\begin{tikzpicture}[auto]
1381
\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1382
\& \& \& \nodea \& \\
1383
\& \nodeb \& \& \nodef \& \nodeg \\
1384
\nodec \& \noded \& \nodee \& \& \\
1385
};
1386
<BLANKLINE>
1387
\path[ultra thick, red] (b) edge (c) edge (d) edge (e)
1388
(a) edge (b) edge (f) edge (g);
1389
\end{tikzpicture}}
1390
"""
1391
# build all subtree matrices.
1392
node, name = create_node(self)
1393
edge = [name]
1394
split = int(len(self) / 2)
1395
# the left part
1396
for i in range(split):
1397
tmp(self[i], edge, nodes, edges, matrix)
1398
# # prepare the root line
1399
if len(matrix) != 0:
1400
nb_of_and = matrix[0].count(sep)
1401
sizetmp = len(matrix[0])
1402
else:
1403
nb_of_and = 0
1404
sizetmp = 0
1405
# the middle
1406
tmp(self[split], edge, nodes, edges, matrix)
1407
nb_of_and += matrix[0][sizetmp:].split("node")[0].count(sep)
1408
1409
# the right part
1410
for i in range(split + 1, len(self)):
1411
tmp(self[i], edge, nodes, edges, matrix)
1412
1413
# # create the root line
1414
root_line = (spacesep * (nb_of_and) + node_to_str(node) +
1415
sepspace * (matrix[0].count(sep) - nb_of_and))
1416
matrix.insert(0, root_line)
1417
# add edges from the root
1418
edges.append(edge)
1419
if self.is_empty():
1420
empty_tree()
1421
elif len(self) == 0 or all(subtree.is_empty()
1422
for subtree in self):
1423
one_node_tree(self)
1424
elif len(self) % 2 == 0:
1425
pair_nodes_tree(self, nodes, edges, matrix)
1426
else:
1427
odd_nodes_tree(self, nodes, edges, matrix)
1428
return nodes, matrix, edges
1429
1430
nodes, matrix, edges = resolve(self)
1431
1432
def make_cmd(nodes):
1433
cmds = []
1434
for name, label in nodes:
1435
cmds.append(new_cmd1 + name + new_cmd2 +
1436
name + new_cmd3 +
1437
label + new_cmd4)
1438
return cmds
1439
1440
def make_edges(edges):
1441
all_paths = []
1442
for edge in edges:
1443
path = "(" + edge[0] + ")"
1444
for i in range(1, len(edge)):
1445
path += " edge (%s)" % edge[i]
1446
all_paths.append(path)
1447
return all_paths
1448
return ("{ " +
1449
"".join(make_cmd(nodes)) +
1450
begin_env +
1451
(matrix_begin +
1452
"\\\\ \n".join(matrix) +
1453
matrix_end +
1454
("\n" +
1455
path_begin +
1456
"\n\t".join(make_edges(edges)) +
1457
path_end if len(edges) > 0 else "")
1458
if len(matrix) > 0 else "") +
1459
end_env +
1460
"}")
1461
1462
1463
class AbstractClonableTree(AbstractTree):
1464
"""
1465
Abstract Clonable Tree.
1466
1467
An abstract class for trees with clone protocol (see
1468
:mod:`~sage.structure.list_clone`). It is expected that classes extending
1469
this one may also inherit from classes like :class:`ClonableArray` or
1470
:class:`~sage.structure.list_clone.ClonableList` depending whether one
1471
wants to build trees where adding a child is allowed.
1472
1473
.. NOTE:: Due to the limitation of Cython inheritance, one cannot inherit
1474
here from :class:`~sage.structure.list_clone.ClonableElement`, because
1475
it would prevent us from later inheriting from
1476
:class:`~sage.structure.list_clone.ClonableArray` or
1477
:class:`~sage.structure.list_clone.ClonableList`.
1478
1479
.. rubric:: How should this class be extended ?
1480
1481
A class extending :class:`AbstractClonableTree
1482
<sage.combinat.abstract_tree.AbstractClonableTree>` should satisfy the
1483
following assumptions:
1484
1485
* An instantiable class extending :class:`AbstractClonableTree
1486
<sage.combinat.abstract_tree.AbstractClonableTree>` should also extend
1487
the :class:`ClonableElement <sage.structure.list_clone.ClonableElement>`
1488
class or one of its subclasses generally, at least :class:`ClonableArray
1489
<sage.structure.list_clone.ClonableArray>`.
1490
1491
* To respect the Clone protocol, the :meth:`AbstractClonableTree.check`
1492
method should be overridden by the new class.
1493
1494
See also the assumptions in :class:`AbstractTree`.
1495
"""
1496
def check(self):
1497
"""
1498
Check that ``self`` is a correct tree.
1499
1500
This method does nothing. It is implemented here because many
1501
extensions of :class:`AbstractClonableTree
1502
<sage.combinat.abstract_tree.AbstractClonableTree>` also extend
1503
:class:`sage.structure.list_clone.ClonableElement`, which requires it.
1504
1505
It should be overridden in subclasses in order to check that the
1506
characterizing property of the respective kind of tree holds (eg: two
1507
children for binary trees).
1508
1509
EXAMPLES::
1510
1511
sage: OrderedTree([[],[[]]]).check()
1512
sage: BinaryTree([[],[[],[]]]).check()
1513
"""
1514
pass
1515
1516
def __setitem__(self, idx, value):
1517
"""
1518
Substitute a subtree
1519
1520
.. NOTE::
1521
1522
The tree ``self`` must be in a mutable state. See
1523
:mod:`sage.structure.list_clone` for more details about
1524
mutability. The default implementation here assume that the
1525
container of the node implement a method `_setitem` with signature
1526
`self._setitem(idx, value)`. It is usually provided by inheriting
1527
from :class:`~sage.structure.list_clone.ClonableArray`.
1528
1529
INPUT:
1530
1531
- ``idx`` -- a valid path in ``self`` identifying a node
1532
1533
- ``value`` -- the tree to be substituted
1534
1535
EXAMPLES:
1536
1537
Trying to modify a non mutable tree raises an error::
1538
1539
sage: x = OrderedTree([])
1540
sage: x[0] = OrderedTree([[]])
1541
Traceback (most recent call last):
1542
...
1543
ValueError: object is immutable; please change a copy instead.
1544
1545
Here is the correct way to do it::
1546
1547
sage: x = OrderedTree([[],[[]]])
1548
sage: with x.clone() as x:
1549
....: x[0] = OrderedTree([[]])
1550
sage: x
1551
[[[]], [[]]]
1552
1553
One can also substitute at any depth::
1554
1555
sage: y = OrderedTree(x)
1556
sage: with x.clone() as x:
1557
....: x[0,0] = OrderedTree([[]])
1558
sage: x
1559
[[[[]]], [[]]]
1560
sage: y
1561
[[[]], [[]]]
1562
sage: with y.clone() as y:
1563
....: y[(0,)] = OrderedTree([])
1564
sage: y
1565
[[], [[]]]
1566
1567
This works for binary trees as well::
1568
1569
sage: bt = BinaryTree([[],[[],[]]]); bt
1570
[[., .], [[., .], [., .]]]
1571
sage: with bt.clone() as bt1:
1572
....: bt1[0,0] = BinaryTree([[[], []], None])
1573
sage: bt1
1574
[[[[[., .], [., .]], .], .], [[., .], [., .]]]
1575
1576
TESTS::
1577
1578
sage: x = OrderedTree([])
1579
sage: with x.clone() as x:
1580
....: x[0] = OrderedTree([[]])
1581
Traceback (most recent call last):
1582
....:
1583
IndexError: list assignment index out of range
1584
1585
sage: x = OrderedTree([]); x = OrderedTree([x,x]); x = OrderedTree([x,x]); x = OrderedTree([x,x])
1586
sage: with x.clone() as x:
1587
....: x[0,0] = OrderedTree()
1588
sage: x
1589
[[[], [[], []]], [[[], []], [[], []]]]
1590
"""
1591
if not isinstance(value, self.__class__):
1592
raise TypeError('the given value is not a tree')
1593
if isinstance(idx, tuple):
1594
self.__setitem_rec__(idx, 0, value)
1595
else:
1596
self._setitem(idx, value)
1597
1598
def __setitem_rec__(self, idx, i, value):
1599
"""
1600
TESTS::
1601
1602
sage: x = OrderedTree([[[], []],[[]]])
1603
sage: with x.clone() as x:
1604
....: x[0,1] = OrderedTree([[[]]]) # indirect doctest
1605
sage: x
1606
[[[], [[[]]]], [[]]]
1607
"""
1608
if i == len(idx) - 1:
1609
self._setitem(idx[-1], value)
1610
else:
1611
with self[idx[i]].clone() as child:
1612
child.__setitem_rec__(idx, i+1, value)
1613
self[idx[i]] = child
1614
1615
def __getitem__(self, idx):
1616
"""
1617
Return the ``idx``-th child of ``self`` (which is a subtree) if
1618
``idx`` is an integer, or the ``idx[n-1]``-th child of the
1619
``idx[n-2]``-th child of the ... of the ``idx[0]``-th child of
1620
``self`` if ``idx`` is a list (or iterable) of length `n`.
1621
1622
The indexing of the children is zero-based.
1623
1624
INPUT:
1625
1626
- ``idx`` -- an integer, or a valid path in ``self`` identifying a node
1627
1628
.. NOTE::
1629
1630
The default implementation here assumes that the container of the
1631
node inherits from
1632
:class:`~sage.structure.list_clone.ClonableArray`.
1633
1634
EXAMPLES::
1635
1636
sage: x = OrderedTree([[],[[]]])
1637
sage: x[1,0]
1638
[]
1639
sage: x = OrderedTree([[],[[]]])
1640
sage: x[()]
1641
[[], [[]]]
1642
sage: x[(0,)]
1643
[]
1644
sage: x[0,0]
1645
Traceback (most recent call last):
1646
...
1647
IndexError: list index out of range
1648
1649
sage: u = BinaryTree(None)
1650
sage: v = BinaryTree([u, u])
1651
sage: w = BinaryTree([u, v])
1652
sage: t = BinaryTree([v, w])
1653
sage: z = BinaryTree([w, t])
1654
sage: z[0,1]
1655
[., .]
1656
sage: z[0,0]
1657
.
1658
sage: z[1]
1659
[[., .], [., [., .]]]
1660
sage: z[1,1]
1661
[., [., .]]
1662
sage: z[1][1,1]
1663
[., .]
1664
"""
1665
if isinstance(idx, slice):
1666
return ClonableArray.__getitem__(self, idx)
1667
try:
1668
i = int(idx)
1669
except TypeError:
1670
res = self
1671
# idx is supposed to be an iterable of ints
1672
for i in idx:
1673
res = ClonableArray._getitem(res, i)
1674
return res
1675
else:
1676
return ClonableArray._getitem(self, i)
1677
1678
1679
class AbstractLabelledTree(AbstractTree):
1680
"""
1681
Abstract Labelled Tree.
1682
1683
Typically a class for labelled trees is contructed by inheriting from
1684
a class for unlabelled trees and :class:`AbstractLabelledTree`.
1685
1686
.. rubric:: How should this class be extended ?
1687
1688
A class extending :class:`AbstractLabelledTree
1689
<sage.combinat.abstract_tree.AbstractLabelledTree>` should respect the
1690
following assumptions:
1691
1692
* For a labelled tree ``T`` the call ``T.parent().unlabelled_trees()``
1693
should return a parent for unlabelled trees of the same kind: for
1694
example,
1695
1696
- if ``T`` is a binary labelled tree, ``T.parent()`` is
1697
``LabelledBinaryTrees()`` and ``T.parent().unlabelled_trees()`` is
1698
``BinaryTrees()``
1699
1700
- if ``T`` is an ordered labelled tree, ``T.parent()`` is
1701
``LabelledOrderedTrees()`` and ``T.parent().unlabelled_trees()`` is
1702
``OrderedTrees()``
1703
1704
* In the same vein, the class of ``T`` should contain an attribute
1705
``_UnLabelled`` which should be the class for the corresponding
1706
unlabelled trees.
1707
1708
See also the assumptions in :class:`AbstractTree`.
1709
1710
.. SEEALSO:: :class:`AbstractTree`
1711
"""
1712
def __init__(self, parent, children, label = None, check = True):
1713
"""
1714
TESTS::
1715
1716
sage: LabelledOrderedTree([])
1717
None[]
1718
sage: LabelledOrderedTree([], 3)
1719
3[]
1720
sage: LT = LabelledOrderedTree
1721
sage: t = LT([LT([LT([], label=42), LT([], 21)])], label=1)
1722
sage: t
1723
1[None[42[], 21[]]]
1724
sage: LabelledOrderedTree(OrderedTree([[],[[],[]],[]]))
1725
None[None[], None[None[], None[]], None[]]
1726
"""
1727
# We must initialize the label before the subtrees to allows rooted
1728
# trees canonization. Indeed it needs that ``self``._hash_() is working
1729
# at the end of the call super(..., self).__init__(...)
1730
if isinstance(children, self.__class__):
1731
if label is None:
1732
self._label = children._label
1733
else:
1734
self._label = label
1735
else:
1736
self._label = label
1737
super(AbstractLabelledTree, self).__init__(parent, children, check=check)
1738
1739
def _repr_(self):
1740
"""
1741
Returns the string representation of ``self``
1742
1743
TESTS::
1744
1745
sage: LabelledOrderedTree([]) # indirect doctest
1746
None[]
1747
sage: LabelledOrderedTree([], label=3) # indirect doctest
1748
3[]
1749
sage: LabelledOrderedTree([[],[[]]]) # indirect doctest
1750
None[None[], None[None[]]]
1751
sage: LabelledOrderedTree([[],LabelledOrderedTree([[]], label=2)], label=3)
1752
3[None[], 2[None[]]]
1753
"""
1754
return "%s%s"%(self._label, self[:])
1755
1756
def label(self, path=None):
1757
"""
1758
Return the label of ``self``.
1759
1760
INPUT:
1761
1762
- ``path`` -- None (default) or a path (list or tuple of children index
1763
in the tree)
1764
1765
OUTPUT: the label of the subtree indexed by ``path``
1766
1767
EXAMPLES::
1768
1769
sage: t = LabelledOrderedTree([[],[]], label = 3)
1770
sage: t.label()
1771
3
1772
sage: t[0].label()
1773
sage: t = LabelledOrderedTree([LabelledOrderedTree([], 5),[]], label = 3)
1774
sage: t.label()
1775
3
1776
sage: t[0].label()
1777
5
1778
sage: t[1].label()
1779
sage: t.label([0])
1780
5
1781
"""
1782
if path is None:
1783
return self._label
1784
else:
1785
tr = self
1786
for i in path:
1787
tr = tr[i]
1788
return tr._label
1789
1790
def labels(self):
1791
"""
1792
Return the list of labels of ``self``.
1793
1794
EXAMPLES::
1795
1796
sage: LT = LabelledOrderedTree
1797
sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
1798
sage: t.labels()
1799
['a', 'b', 'c']
1800
1801
sage: LBT = LabelledBinaryTree
1802
sage: LBT([LBT([],label=1),LBT([],label=4)],label=2).labels()
1803
[2, 1, 4]
1804
"""
1805
return [t.label() for t in self.subtrees()]
1806
1807
def leaf_labels(self):
1808
"""
1809
Return the list of labels of the leaves of ``self``.
1810
1811
In case of a labelled binary tree, these "leaves" are not actually
1812
the leaves of the binary trees, but the nodes whose both children
1813
are leaves!
1814
1815
EXAMPLES::
1816
1817
sage: LT = LabelledOrderedTree
1818
sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
1819
sage: t.leaf_labels()
1820
['b', 'c']
1821
1822
sage: LBT = LabelledBinaryTree
1823
sage: bt = LBT([LBT([],label='b'),LBT([],label='c')],label='a')
1824
sage: bt.leaf_labels()
1825
['b', 'c']
1826
sage: LBT([], label='1').leaf_labels()
1827
['1']
1828
sage: LBT(None).leaf_labels()
1829
[]
1830
"""
1831
return [t.label() for t in self.subtrees() if t.node_number()==1]
1832
1833
def __eq__(self, other):
1834
"""
1835
Tests if ``self`` is equal to ``other``
1836
1837
TESTS::
1838
1839
sage LabelledOrderedTree() == LabelledOrderedTree()
1840
True
1841
sage LabelledOrderedTree([]) == LabelledOrderedTree()
1842
False
1843
sage: t1 = LabelledOrderedTree([[],[[]]])
1844
sage: t2 = LabelledOrderedTree([[],[[]]])
1845
sage: t1 == t2
1846
True
1847
sage: t2 = LabelledOrderedTree(t1)
1848
sage: t1 == t2
1849
True
1850
sage: t1 = LabelledOrderedTree([[],[[]]])
1851
sage: t2 = LabelledOrderedTree([[[]],[]])
1852
sage: t1 == t2
1853
False
1854
"""
1855
return ( super(AbstractLabelledTree, self).__eq__(other) and
1856
self._label == other._label )
1857
1858
def _hash_(self):
1859
"""
1860
Returns the hash value for ``self``
1861
1862
TESTS::
1863
1864
sage: t1 = LabelledOrderedTree([[],[[]]], label = 1); t1hash = t1.__hash__()
1865
sage: LabelledOrderedTree([[],[[]]], label = 1).__hash__() == t1hash
1866
True
1867
sage: LabelledOrderedTree([[[]],[]], label = 1).__hash__() == t1hash
1868
False
1869
sage: LabelledOrderedTree(t1, label = 1).__hash__() == t1hash
1870
True
1871
sage: LabelledOrderedTree([[],[[]]], label = 25).__hash__() == t1hash
1872
False
1873
sage: LabelledOrderedTree(t1, label = 25).__hash__() == t1hash
1874
False
1875
1876
sage: LabelledBinaryTree([[],[[],[]]], label = 25).__hash__() #random
1877
8544617749928727644
1878
1879
We check that the hash value depends on the value of the labels of the
1880
subtrees::
1881
1882
sage: LBT = LabelledBinaryTree
1883
sage: t1 = LBT([], label = 1)
1884
sage: t2 = LBT([], label = 2)
1885
sage: t3 = LBT([], label = 3)
1886
sage: t12 = LBT([t1, t2], label = "a")
1887
sage: t13 = LBT([t1, t3], label = "a")
1888
sage: t12.__hash__() != t13.__hash__()
1889
True
1890
"""
1891
return self._UnLabelled._hash_(self) ^ hash(self._label)
1892
1893
def shape(self):
1894
"""
1895
Returns the unlabelled tree associated to ``self``
1896
1897
EXAMPLES::
1898
1899
sage: t = LabelledOrderedTree([[],[[]]], label = 25).shape(); t
1900
[[], [[]]]
1901
1902
sage: LabelledBinaryTree([[],[[],[]]], label = 25).shape()
1903
[[., .], [[., .], [., .]]]
1904
1905
TESTS::
1906
1907
sage: t.parent()
1908
Ordered trees
1909
sage: type(t)
1910
<class 'sage.combinat.ordered_tree.OrderedTrees_all_with_category.element_class'>
1911
"""
1912
TR = self.parent().unlabelled_trees()
1913
if not self:
1914
return TR.leaf()
1915
else:
1916
return TR._element_constructor_([i.shape() for i in self])
1917
1918
def as_digraph(self):
1919
"""
1920
Returns a directed graph version of ``self``.
1921
1922
.. WARNING::
1923
1924
At this time, the output makes sense only if ``self`` is a
1925
labelled binary tree with no repeated labels and no ``None``
1926
labels.
1927
1928
EXAMPLES::
1929
1930
sage: LT = LabelledOrderedTrees()
1931
sage: t1 = LT([LT([],label=6),LT([],label=1)],label=9)
1932
sage: t1.as_digraph()
1933
Digraph on 3 vertices
1934
1935
sage: t = BinaryTree([[None, None],[[],None]]);
1936
sage: lt = t.canonical_labelling()
1937
sage: lt.as_digraph()
1938
Digraph on 4 vertices
1939
"""
1940
from sage.graphs.digraph import DiGraph
1941
resu = dict([[self.label(),
1942
[t.label() for t in self if not t.is_empty()]]])
1943
resu = DiGraph(resu)
1944
for t in self:
1945
if not t.is_empty():
1946
resu = resu.union(t.as_digraph())
1947
return resu
1948
1949
1950
class AbstractLabelledClonableTree(AbstractLabelledTree,
1951
AbstractClonableTree):
1952
"""
1953
Abstract Labelled Clonable Tree
1954
1955
This class takes care of modification for the label by the clone protocol.
1956
1957
.. NOTE:: Due to the limitation of Cython inheritance, one cannot inherit
1958
here from :class:`ClonableArray`, because it would prevent us to
1959
inherit later from :class:`~sage.structure.list_clone.ClonableList`.
1960
"""
1961
def set_root_label(self, label):
1962
"""
1963
Sets the label of the root of ``self``
1964
1965
INPUT: ``label`` -- any Sage object
1966
1967
OUPUT: ``None``, ``self`` is modified in place
1968
1969
.. NOTE::
1970
1971
``self`` must be in a mutable state. See
1972
:mod:`sage.structure.list_clone` for more details about
1973
mutability.
1974
1975
EXAMPLES::
1976
1977
sage: t = LabelledOrderedTree([[],[[],[]]])
1978
sage: t.set_root_label(3)
1979
Traceback (most recent call last):
1980
...
1981
ValueError: object is immutable; please change a copy instead.
1982
sage: with t.clone() as t:
1983
....: t.set_root_label(3)
1984
sage: t.label()
1985
3
1986
sage: t
1987
3[None[], None[None[], None[]]]
1988
1989
This also works for binary trees::
1990
1991
sage: bt = LabelledBinaryTree([[],[]])
1992
sage: bt.set_root_label(3)
1993
Traceback (most recent call last):
1994
...
1995
ValueError: object is immutable; please change a copy instead.
1996
sage: with bt.clone() as bt:
1997
....: bt.set_root_label(3)
1998
sage: bt.label()
1999
3
2000
sage: bt
2001
3[None[., .], None[., .]]
2002
2003
TESTS::
2004
2005
sage: with t.clone() as t:
2006
....: t[0] = LabelledOrderedTree(t[0], label = 4)
2007
sage: t
2008
3[4[], None[None[], None[]]]
2009
sage: with t.clone() as t:
2010
....: t[1,0] = LabelledOrderedTree(t[1,0], label = 42)
2011
sage: t
2012
3[4[], None[42[], None[]]]
2013
"""
2014
self._require_mutable()
2015
self._label = label
2016
2017
def set_label(self, path, label):
2018
"""
2019
Changes the label of subtree indexed by ``path`` to ``label``
2020
2021
INPUT:
2022
2023
- ``path`` -- ``None`` (default) or a path (list or tuple of children
2024
index in the tree)
2025
2026
- ``label`` -- any sage object
2027
2028
OUPUT: Nothing, ``self`` is modified in place
2029
2030
.. NOTE::
2031
2032
``self`` must be in a mutable state. See
2033
:mod:`sage.structure.list_clone` for more details about
2034
mutability.
2035
2036
EXAMPLES::
2037
2038
sage: t = LabelledOrderedTree([[],[[],[]]])
2039
sage: t.set_label((0,), 4)
2040
Traceback (most recent call last):
2041
...
2042
ValueError: object is immutable; please change a copy instead.
2043
sage: with t.clone() as t:
2044
....: t.set_label((0,), 4)
2045
sage: t
2046
None[4[], None[None[], None[]]]
2047
sage: with t.clone() as t:
2048
....: t.set_label((1,0), label = 42)
2049
sage: t
2050
None[4[], None[42[], None[]]]
2051
2052
.. TODO::
2053
2054
Do we want to implement the following syntactic sugar::
2055
2056
with t.clone() as tt:
2057
tt.labels[1,2] = 3 ?
2058
"""
2059
self._require_mutable()
2060
path = tuple(path)
2061
if path == ():
2062
self._label = label
2063
else:
2064
with self[path[0]].clone() as child:
2065
child.set_label(path[1:], label)
2066
self[path[0]] = child
2067
2068
def map_labels(self, f):
2069
"""
2070
Applies the function `f` to the labels of ``self``
2071
2072
This method returns a copy of ``self`` on which the function `f` has
2073
been applied on all labels (a label `x` is replaced by `f(x)`).
2074
2075
EXAMPLES::
2076
2077
sage: LT = LabelledOrderedTree
2078
sage: t = LT([LT([],label=1),LT([],label=7)],label=3); t
2079
3[1[], 7[]]
2080
sage: t.map_labels(lambda z:z+1)
2081
4[2[], 8[]]
2082
2083
sage: LBT = LabelledBinaryTree
2084
sage: bt = LBT([LBT([],label=1),LBT([],label=4)],label=2); bt
2085
2[1[., .], 4[., .]]
2086
sage: bt.map_labels(lambda z:z+1)
2087
3[2[., .], 5[., .]]
2088
"""
2089
if self.is_empty():
2090
return self
2091
return self.parent()([t.map_labels(f) for t in self],
2092
label=f(self.label()))
2093
2094
2095
def from_hexacode(ch, parent=None, label='@'):
2096
r"""
2097
Transform an hexadecimal string into a tree.
2098
2099
INPUT:
2100
2101
- ``ch`` -- an hexadecimal string
2102
2103
- ``parent`` -- kind of trees to be produced. If ``None``, this will
2104
be ``LabelledOrderedTrees``
2105
2106
- ``label`` -- a label (default: ``'@'``) to be used for every vertex
2107
of the tree
2108
2109
See :meth:`AbstractTree.to_hexacode` for the description of the encoding
2110
2111
See :func:`_from_hexacode_aux` for the actual code
2112
2113
EXAMPLES::
2114
2115
sage: from sage.combinat.abstract_tree import from_hexacode
2116
sage: from_hexacode('12000', LabelledOrderedTrees())
2117
@[@[@[], @[]]]
2118
2119
sage: from_hexacode('1200', LabelledOrderedTrees())
2120
@[@[@[], @[]]]
2121
2122
It can happen that only a prefix of the word is used::
2123
2124
sage: from_hexacode('a'+14*'0', LabelledOrderedTrees())
2125
@[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]]
2126
2127
One can choose the label::
2128
2129
sage: from_hexacode('1200', LabelledOrderedTrees(), label='o')
2130
o[o[o[], o[]]]
2131
2132
One can also create other kinds of trees::
2133
2134
sage: from_hexacode('1200', OrderedTrees())
2135
[[[], []]]
2136
"""
2137
if parent is None:
2138
from sage.combinat.rooted_tree import LabelledOrderedTrees
2139
parent = LabelledOrderedTrees()
2140
return _from_hexacode_aux(ch, parent, label)[0]
2141
2142
2143
def _from_hexacode_aux(ch, parent, label='@'):
2144
r"""
2145
Transform an hexadecimal string into a tree and a remainder string.
2146
2147
INPUT:
2148
2149
- ``ch`` -- an hexadecimal string
2150
2151
- ``parent`` -- kind of trees to be produced.
2152
2153
- ``label`` -- a label (default: ``'@'``) to be used for every vertex
2154
of the tree
2155
2156
This method is used in :func:`from_hexacode`
2157
2158
EXAMPLES::
2159
2160
sage: from sage.combinat.abstract_tree import _from_hexacode_aux
2161
sage: _from_hexacode_aux('12000', LabelledOrderedTrees())
2162
(@[@[@[], @[]]], '0')
2163
2164
sage: _from_hexacode_aux('1200', LabelledOrderedTrees())
2165
(@[@[@[], @[]]], '')
2166
2167
sage: _from_hexacode_aux('1200', OrderedTrees())
2168
([[[], []]], '')
2169
2170
sage: _from_hexacode_aux('a00000000000000', LabelledOrderedTrees())
2171
(@[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]], '0000')
2172
"""
2173
Trees = parent
2174
width = int(ch[0], 16) # hexadecimal input
2175
remainder = ch[1:]
2176
if width == 0:
2177
return (Trees([], label), remainder)
2178
branches = {}
2179
for i in range(width):
2180
tree, remainder = _from_hexacode_aux(remainder, parent, label)
2181
branches[i] = tree
2182
return (Trees(branches.values(), label), remainder)
2183
2184