Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/binary_tree.py
8815 views
1
# -*- coding: utf-8 -*-
2
"""
3
Binary Trees.
4
5
This module deals with binary trees as mathematical (in particular immutable)
6
objects.
7
8
.. NOTE::
9
10
If you need the data-structure for example to represent sets or hash
11
tables with AVL trees, you should have a look at :mod:`sage.misc.sagex_ds`.
12
13
AUTHORS:
14
15
- Florent Hivert (2010-2011): initial implementation.
16
17
REFERENCES:
18
19
.. [LodayRonco] Jean-Louis Loday and Maria O. Ronco.
20
*Hopf algebra of the planar binary trees*,
21
Advances in Mathematics, volume 139, issue 2,
22
10 November 1998, pp. 293-309.
23
http://www.sciencedirect.com/science/article/pii/S0001870898917595
24
25
.. [HNT05] Florent Hivert, Jean-Christophe Novelli, and Jean-Yves Thibon.
26
*The algebra of binary search trees*,
27
:arxiv:`math/0401089v2`.
28
29
.. [CP12] Gregory Chatel, Viviane Pons.
30
*Counting smaller trees in the Tamari order*,
31
:arxiv:`1212.0751v1`.
32
"""
33
#*****************************************************************************
34
# Copyright (C) 2010 Florent Hivert <[email protected]>,
35
#
36
# Distributed under the terms of the GNU General Public License (GPL)
37
# as published by the Free Software Foundation; either version 2 of
38
# the License, or (at your option) any later version.
39
# http://www.gnu.org/licenses/
40
#*****************************************************************************
41
from sage.structure.list_clone import ClonableArray
42
from sage.combinat.abstract_tree import (AbstractClonableTree,
43
AbstractLabelledClonableTree)
44
from sage.combinat.ordered_tree import LabelledOrderedTrees
45
from sage.rings.integer import Integer
46
from sage.misc.classcall_metaclass import ClasscallMetaclass
47
from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute
48
from sage.combinat.combinatorial_map import combinatorial_map
49
50
class BinaryTree(AbstractClonableTree, ClonableArray):
51
"""
52
Binary trees.
53
54
Binary trees here mean ordered (a.k.a. plane) finite binary
55
trees, where "ordered" means that the children of each node are
56
ordered.
57
58
Binary trees contain nodes and leaves, where each node has two
59
children while each leaf has no children. The number of leaves
60
of a binary tree always equals the number of nodes plus `1`.
61
62
INPUT:
63
64
- ``children`` -- ``None`` (default) or a list, tuple or iterable of
65
length `2` of binary trees or convertible objects. This corresponds
66
to the standard recursive definition of a binary tree as either a
67
leaf or a pair of binary trees. Syntactic sugar allows leaving out
68
all but the outermost calls of the ``BinaryTree()`` constructor, so
69
that, e. g., ``BinaryTree([BinaryTree(None),BinaryTree(None)])`` can
70
be shortened to ``BinaryTree([None,None])``. It is also allowed to
71
abbreviate ``[None, None]`` by ``[]``.
72
73
- ``check`` -- (default: ``True``) whether check for binary should be
74
performed or not.
75
76
EXAMPLES::
77
78
sage: BinaryTree()
79
.
80
sage: BinaryTree(None)
81
.
82
sage: BinaryTree([])
83
[., .]
84
sage: BinaryTree([None, None])
85
[., .]
86
sage: BinaryTree([None, []])
87
[., [., .]]
88
sage: BinaryTree([[], None])
89
[[., .], .]
90
sage: BinaryTree("[[], .]")
91
[[., .], .]
92
sage: BinaryTree([None, BinaryTree([None, None])])
93
[., [., .]]
94
95
sage: BinaryTree([[], None, []])
96
Traceback (most recent call last):
97
...
98
ValueError: this is not a binary tree
99
100
TESTS::
101
102
sage: t1 = BinaryTree([[None, [[],[[], None]]],[[],[]]])
103
sage: t2 = BinaryTree([[[],[]],[]])
104
sage: with t1.clone() as t1c:
105
....: t1c[1,1,1] = t2
106
sage: t1 == t1c
107
False
108
"""
109
__metaclass__ = ClasscallMetaclass
110
111
@staticmethod
112
def __classcall_private__(cls, *args, **opts):
113
"""
114
Ensure that binary trees created by the enumerated sets and directly
115
are the same and that they are instances of :class:`BinaryTree`.
116
117
TESTS::
118
119
sage: from sage.combinat.binary_tree import BinaryTrees_all
120
sage: issubclass(BinaryTrees_all().element_class, BinaryTree)
121
True
122
sage: t0 = BinaryTree([[],[[], None]])
123
sage: t0.parent()
124
Binary trees
125
sage: type(t0)
126
<class 'sage.combinat.binary_tree.BinaryTrees_all_with_category.element_class'>
127
128
sage: t1 = BinaryTrees()([[],[[], None]])
129
sage: t1.parent() is t0.parent()
130
True
131
sage: type(t1) is type(t0)
132
True
133
134
sage: t1 = BinaryTrees(4)([[],[[], None]])
135
sage: t1.parent() is t0.parent()
136
True
137
sage: type(t1) is type(t0)
138
True
139
"""
140
return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
141
142
@lazy_class_attribute
143
def _auto_parent(cls):
144
"""
145
The automatic parent of the elements of this class.
146
147
When calling the constructor of an element of this class, one needs a
148
parent. This class attribute specifies which parent is used.
149
150
EXAMPLES::
151
152
sage: BinaryTree._auto_parent
153
Binary trees
154
sage: BinaryTree([None, None]).parent()
155
Binary trees
156
"""
157
return BinaryTrees_all()
158
159
def __init__(self, parent, children = None, check = True):
160
"""
161
TESTS::
162
163
sage: BinaryTree([None, None]).parent()
164
Binary trees
165
sage: BinaryTree("[., [., [., .]]]")
166
[., [., [., .]]]
167
sage: BinaryTree("[.,.,.]")
168
Traceback (most recent call last):
169
...
170
ValueError: this is not a binary tree
171
sage: all(BinaryTree(repr(bt)) == bt for i in range(6) for bt in BinaryTrees(i))
172
True
173
"""
174
if (type(children) is str): # if the input is the repr of a binary tree
175
children = children.replace(".","None")
176
from ast import literal_eval
177
children = literal_eval(children)
178
if children is None:
179
children = []
180
elif (children == [] or children == ()
181
or isinstance(children, (Integer, int))):
182
children = [None, None]
183
if (children.__class__ is self.__class__ and
184
children.parent() == parent):
185
children = list(children)
186
else:
187
children = [self.__class__(parent, x) for x in children]
188
ClonableArray.__init__(self, parent, children, check=check)
189
190
def check(self):
191
"""
192
Check that ``self`` is a binary tree.
193
194
EXAMPLES::
195
196
sage: BinaryTree([[], []]) # indirect doctest
197
[[., .], [., .]]
198
sage: BinaryTree([[], [], []]) # indirect doctest
199
Traceback (most recent call last):
200
...
201
ValueError: this is not a binary tree
202
sage: BinaryTree([[]]) # indirect doctest
203
Traceback (most recent call last):
204
...
205
ValueError: this is not a binary tree
206
"""
207
if not (not self or len(self) == 2):
208
raise ValueError("this is not a binary tree")
209
210
def _repr_(self):
211
"""
212
TESTS::
213
214
sage: t1 = BinaryTree([[], None]); t1 # indirect doctest
215
[[., .], .]
216
sage: BinaryTree([[None, t1], None]) # indirect doctest
217
[[., [[., .], .]], .]
218
"""
219
if not self:
220
return "."
221
else:
222
return super(BinaryTree, self)._repr_()
223
224
def _ascii_art_( self ):
225
r"""
226
TESTS::
227
228
sage: ascii_art(BinaryTree())
229
<BLANKLINE>
230
sage: ascii_art(BinaryTree([]))
231
o
232
sage: for bt in BinaryTrees(3):
233
....: print ascii_art(bt)
234
o
235
\
236
o
237
\
238
o
239
o
240
\
241
o
242
/
243
o
244
o
245
/ \
246
o o
247
o
248
/
249
o
250
\
251
o
252
o
253
/
254
o
255
/
256
o
257
sage: ascii_art(BinaryTree([None,[]]))
258
o
259
\
260
o
261
sage: ascii_art(BinaryTree([None,[None,[]]]))
262
o
263
\
264
o
265
\
266
o
267
sage: ascii_art(BinaryTree([None,[[],None]]))
268
o
269
\
270
o
271
/
272
o
273
sage: ascii_art(BinaryTree([None,[[[],[]],[]]]))
274
o
275
\
276
_o_
277
/ \
278
o o
279
/ \
280
o o
281
sage: ascii_art(BinaryTree([None,[[None,[[],[]]],None]]))
282
o
283
\
284
o
285
/
286
o
287
\
288
o
289
/ \
290
o o
291
sage: ascii_art(BinaryTree([[],None]))
292
o
293
/
294
o
295
sage: ascii_art(BinaryTree([[[[],None], None],None]))
296
o
297
/
298
o
299
/
300
o
301
/
302
o
303
sage: ascii_art(BinaryTree([[[],[]],None]))
304
o
305
/
306
o
307
/ \
308
o o
309
sage: ascii_art(BinaryTree([[[None,[]],[[[],None],None]], None]))
310
o
311
/
312
___o___
313
/ \
314
o o
315
\ /
316
o o
317
/
318
o
319
sage: ascii_art(BinaryTree([[None,[[],[]]],None]))
320
o
321
/
322
o
323
\
324
o
325
/ \
326
o o
327
sage: ascii_art(BinaryTree([[],[]]))
328
o
329
/ \
330
o o
331
sage: ascii_art(BinaryTree([[],[[],None]]))
332
_o_
333
/ \
334
o o
335
/
336
o
337
sage: ascii_art(BinaryTree([[None,[]],[[[],None],None]]))
338
___o___
339
/ \
340
o o
341
\ /
342
o o
343
/
344
o
345
sage: ascii_art(BinaryTree([[[],[]],[[],None]]))
346
__o__
347
/ \
348
o o
349
/ \ /
350
o o o
351
sage: ascii_art(BinaryTree([[[],[]],[[],[]]]))
352
__o__
353
/ \
354
o o
355
/ \ / \
356
o o o o
357
sage: ascii_art(BinaryTree([[[[],[]],[[],[]]],[]]))
358
___o___
359
/ \
360
__o__ o
361
/ \
362
o o
363
/ \ / \
364
o o o o
365
sage: ascii_art(BinaryTree([[],[[[[],[]],[[],[]]],[]]]))
366
_____o______
367
/ \
368
o ___o___
369
/ \
370
__o__ o
371
/ \
372
o o
373
/ \ / \
374
o o o o
375
"""
376
node_to_str = lambda bt: str(bt.label()) if hasattr(bt, "label") else "o"
377
378
if self.is_empty():
379
from sage.misc.ascii_art import empty_ascii_art
380
return empty_ascii_art
381
382
from sage.misc.ascii_art import AsciiArt
383
if self[0].is_empty() and self[1].is_empty():
384
bt_repr = AsciiArt( [node_to_str(self)] )
385
bt_repr._root = 1
386
return bt_repr
387
if self[0].is_empty():
388
node = node_to_str(self)
389
rr_tree = self[1]._ascii_art_()
390
if rr_tree._root > 2:
391
f_line = " " ** Integer( rr_tree._root - 3 ) + node
392
s_line = " " ** Integer( len( node ) + rr_tree._root - 3 ) + "\\"
393
t_repr = AsciiArt( [f_line, s_line] ) * rr_tree
394
t_repr._root = rr_tree._root - 2
395
else:
396
f_line = node
397
s_line = " " + "\\"
398
t_line = " " ** Integer( len( node ) + 1 )
399
t_repr = AsciiArt( [f_line, s_line] ) * ( AsciiArt( [t_line] ) + rr_tree )
400
t_repr._root = rr_tree._root
401
t_repr._baseline = t_repr._h - 1
402
return t_repr
403
if self[1].is_empty():
404
node = node_to_str(self)
405
lr_tree = self[0]._ascii_art_()
406
f_line = " " ** Integer( lr_tree._root + 1 ) + node
407
s_line = " " ** Integer( lr_tree._root ) + "/"
408
t_repr = AsciiArt( [f_line, s_line] ) * lr_tree
409
t_repr._root = lr_tree._root + 2
410
t_repr._baseline = t_repr._h - 1
411
return t_repr
412
node = node_to_str(self)
413
lr_tree = self[0]._ascii_art_()
414
rr_tree = self[1]._ascii_art_()
415
nb_ = lr_tree._l - lr_tree._root + rr_tree._root - 1
416
nb_L = int( nb_ / 2 )
417
nb_R = nb_L + ( 1 if nb_ % 2 == 1 else 0 )
418
f_line = " " ** Integer( lr_tree._root + 1 ) + "_" ** Integer( nb_L ) + node
419
f_line += "_" ** Integer( nb_R )
420
s_line = " " ** Integer( lr_tree._root ) + "/" + " " ** Integer( len( node ) + rr_tree._root - 1 + ( lr_tree._l - lr_tree._root ) ) + "\\"
421
t_repr = AsciiArt( [f_line, s_line] ) * ( lr_tree + AsciiArt( [" " ** Integer( len( node ) + 2 )] ) + rr_tree )
422
t_repr._root = lr_tree._root + nb_L + 2
423
t_repr._baseline = t_repr._h - 1
424
return t_repr
425
426
def is_empty(self):
427
"""
428
Return whether ``self`` is empty.
429
430
The notion of emptiness employed here is the one which defines
431
a binary tree to be empty if its root is a leaf. There is
432
precisely one empty binary tree.
433
434
EXAMPLES::
435
436
sage: BinaryTree().is_empty()
437
True
438
sage: BinaryTree([]).is_empty()
439
False
440
sage: BinaryTree([[], None]).is_empty()
441
False
442
"""
443
return not self
444
445
def graph(self, with_leaves=True):
446
"""
447
Convert ``self`` to a digraph. By default, this graph contains
448
both nodes and leaves, hence is never empty. To obtain a graph
449
which contains only the nodes, the ``with_leaves`` optional
450
keyword variable has to be set to ``False``.
451
452
INPUT:
453
454
- ``with_leaves`` -- (default: ``True``) a Boolean, determining
455
whether the resulting graph will be formed from the leaves
456
and the nodes of ``self`` (if ``True``), or only from the
457
nodes of ``self`` (if ``False``)
458
459
EXAMPLES::
460
461
sage: t1 = BinaryTree([[], None])
462
sage: t1.graph()
463
Digraph on 5 vertices
464
sage: t1.graph(with_leaves=False)
465
Digraph on 2 vertices
466
467
sage: t1 = BinaryTree([[], [[], None]])
468
sage: t1.graph()
469
Digraph on 9 vertices
470
sage: t1.graph().edges()
471
[(0, 1, None), (0, 4, None), (1, 2, None), (1, 3, None), (4, 5, None), (4, 8, None), (5, 6, None), (5, 7, None)]
472
sage: t1.graph(with_leaves=False)
473
Digraph on 4 vertices
474
sage: t1.graph(with_leaves=False).edges()
475
[(0, 1, None), (0, 2, None), (2, 3, None)]
476
477
sage: t1 = BinaryTree()
478
sage: t1.graph()
479
Digraph on 1 vertex
480
sage: t1.graph(with_leaves=False)
481
Digraph on 0 vertices
482
483
sage: BinaryTree([]).graph()
484
Digraph on 3 vertices
485
sage: BinaryTree([]).graph(with_leaves=False)
486
Digraph on 1 vertex
487
488
sage: t1 = BinaryTree([[], [[], []]])
489
sage: t1.graph(with_leaves=False)
490
Digraph on 5 vertices
491
sage: t1.graph(with_leaves=False).edges()
492
[(0, 1, None), (0, 2, None), (2, 3, None), (2, 4, None)]
493
"""
494
from sage.graphs.graph import DiGraph
495
496
if with_leaves: # We want leaves and nodes.
497
498
# Special treatment for the case when self is empty.
499
# In this case, rec(self, 0) would give a false result.
500
if not self:
501
return DiGraph({0: []})
502
503
res = DiGraph()
504
# The edge set of res will be built up step by step using the
505
# following function:
506
def rec(tr, idx):
507
if not tr: # tr is a leaf.
508
return
509
else: # tr is a node.
510
nbl = 2 * tr[0].node_number() + 1
511
res.add_edges([[idx, idx + 1], [idx, idx + 1 + nbl]])
512
rec(tr[0], idx + 1)
513
rec(tr[1], idx + nbl + 1)
514
rec(self, 0)
515
return res
516
517
else: # We want only the nodes.
518
519
# Special treatment for the case when self has only 1 node.
520
# In this case, the general DiGraph construction would
521
# falsely yield an empty graph (since it adds nodes only
522
# implicitly by adding edges).
523
if self.node_number() == 1:
524
return DiGraph({0: []})
525
526
res = DiGraph()
527
# The edge set of res will be built up step by step using the
528
# following function:
529
def rec(tr, idx):
530
if not tr: # tr is a leaf.
531
return
532
else: # tr is a node.
533
nbl = tr[0].node_number()
534
if nbl > 0:
535
res.add_edge([idx, idx + 1])
536
rec(tr[0], idx + 1)
537
if tr[1].node_number() > 0:
538
res.add_edge([idx, idx + nbl + 1])
539
rec(tr[1], idx + nbl + 1)
540
rec(self, 0)
541
return res
542
543
def canonical_labelling(self, shift=1):
544
r"""
545
Return a labelled version of ``self``.
546
547
The canonical labelling of a binary tree is a certain labelling of the
548
nodes (not the leaves) of the tree.
549
The actual canonical labelling is currently unspecified. However, it
550
is guaranteed to have labels in `1...n` where `n` is the number of
551
nodes of the tree. Moreover, two (unlabelled) trees compare as equal if
552
and only if their canonical labelled trees compare as equal.
553
554
EXAMPLES::
555
556
sage: BinaryTree().canonical_labelling()
557
.
558
sage: BinaryTree([]).canonical_labelling()
559
1[., .]
560
sage: BinaryTree([[[], [[], None]], [[], []]]).canonical_labelling()
561
5[2[1[., .], 4[3[., .], .]], 7[6[., .], 8[., .]]]
562
"""
563
LTR = self.parent().labelled_trees()
564
if self:
565
sz0 = self[0].node_number()
566
return LTR([self[0].canonical_labelling(shift),
567
self[1].canonical_labelling(shift+1+sz0)],
568
label=shift+sz0)
569
else:
570
return LTR(None)
571
572
def show(self, with_leaves=False):
573
"""
574
Show the binary tree ``show``, with or without leaves depending
575
on the Boolean keyword variable ``with_leaves``.
576
577
.. WARNING::
578
579
Left and right children might get interchanged in
580
the actual picture. Moreover, for a labelled binary
581
tree, the labels shown in the picture are not (in
582
general) the ones given by the labelling!
583
584
Use :meth:`_latex_`, ``view``,
585
:meth:`_ascii_art_` or ``pretty_print`` for more
586
faithful representations of the data of the tree.
587
588
TESTS::
589
590
sage: t1 = BinaryTree([[], [[], None]])
591
sage: t1.show()
592
"""
593
try:
594
self.graph(with_leaves=with_leaves).show(layout='tree', tree_root=0, tree_orientation="down")
595
except RuntimeError:
596
# This is for the border case BinaryTree().show().
597
self.graph(with_leaves=with_leaves).show()
598
599
def make_node(self, child_list = [None, None]):
600
"""
601
Modify ``self`` so that it becomes a node with children ``child_list``.
602
603
INPUT:
604
605
- ``child_list`` -- a pair of binary trees (or objects convertible to)
606
607
.. NOTE:: ``self`` must be in a mutable state.
608
609
.. SEEALSO::
610
611
:meth:`make_leaf <sage.combinat.binary_tree.BinaryTree.make_leaf>`
612
613
EXAMPLES::
614
615
sage: t = BinaryTree()
616
sage: t.make_node([None, None])
617
Traceback (most recent call last):
618
...
619
ValueError: object is immutable; please change a copy instead.
620
sage: with t.clone() as t1:
621
....: t1.make_node([None, None])
622
sage: t, t1
623
(., [., .])
624
sage: with t.clone() as t:
625
....: t.make_node([BinaryTree(), BinaryTree(), BinaryTree([])])
626
Traceback (most recent call last):
627
...
628
ValueError: the list must have length 2
629
sage: with t1.clone() as t2:
630
....: t2.make_node([t1, t1])
631
sage: with t2.clone() as t3:
632
....: t3.make_node([t1, t2])
633
sage: t1, t2, t3
634
([., .], [[., .], [., .]], [[., .], [[., .], [., .]]])
635
"""
636
self._require_mutable()
637
child_lst = [self.__class__(self.parent(), x) for x in child_list]
638
if not(len(child_lst) == 2):
639
raise ValueError("the list must have length 2")
640
self.__init__(self.parent(), child_lst, check=False)
641
642
def make_leaf(self):
643
"""
644
Modify ``self`` so that it becomes a leaf (i. e., an empty tree).
645
646
.. NOTE:: ``self`` must be in a mutable state.
647
648
.. SEEALSO::
649
650
:meth:`make_node <sage.combinat.binary_tree.BinaryTree.make_node>`
651
652
EXAMPLES::
653
654
sage: t = BinaryTree([None, None])
655
sage: t.make_leaf()
656
Traceback (most recent call last):
657
...
658
ValueError: object is immutable; please change a copy instead.
659
sage: with t.clone() as t1:
660
....: t1.make_leaf()
661
sage: t, t1
662
([., .], .)
663
"""
664
self._require_mutable()
665
self.__init__(self.parent(), None)
666
667
def _to_dyck_word_rec(self, usemap="1L0R"):
668
r"""
669
EXAMPLES::
670
671
sage: BinaryTree()._to_dyck_word_rec()
672
[]
673
sage: BinaryTree([])._to_dyck_word_rec()
674
[1, 0]
675
sage: BinaryTree([[[], [[], None]], [[], []]])._to_dyck_word_rec()
676
[1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0]
677
sage: BinaryTree([[None,[]],None])._to_dyck_word_rec("L1R0")
678
[1, 1, 0, 0, 1, 0]
679
sage: BinaryTree([[[], [[], None]], [[], []]])._to_dyck_word_rec("L1R0")
680
[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0]
681
"""
682
if self:
683
w = []
684
for l in usemap:
685
if l == "L": w += self[0]._to_dyck_word_rec(usemap)
686
elif l == "R": w+=self[1]._to_dyck_word_rec(usemap)
687
elif l == "1": w+=[1]
688
elif l == "0": w+=[0]
689
return w
690
else:
691
return []
692
693
@combinatorial_map(name = "to the Tamari corresponding Dyck path")
694
def to_dyck_word_tamari(self):
695
r"""
696
Return the Dyck word associated with ``self`` in consistency with
697
the Tamari order on Dyck words and binary trees.
698
699
The bijection is defined recursively as follows:
700
701
- a leaf is associated with an empty Dyck word
702
703
- a tree with children `l,r` is associated with the Dyck word
704
`T(l) 1 T(r) 0`
705
706
EXAMPLES::
707
708
sage: BinaryTree().to_dyck_word_tamari()
709
[]
710
sage: BinaryTree([]).to_dyck_word_tamari()
711
[1, 0]
712
sage: BinaryTree([[None,[]],None]).to_dyck_word_tamari()
713
[1, 1, 0, 0, 1, 0]
714
sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word_tamari()
715
[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0]
716
"""
717
return self.to_dyck_word("L1R0")
718
719
@combinatorial_map(name="to Dyck paths: up step, left tree, down step, right tree")
720
def to_dyck_word(self, usemap="1L0R"):
721
r"""
722
Return the Dyck word associated with ``self`` using the given map.
723
724
INPUT:
725
726
- ``usemap`` -- a string, either ``1L0R``, ``1R0L``, ``L1R0``, ``R1L0``
727
728
The bijection is defined recursively as follows:
729
730
- a leaf is associated to the empty Dyck Word
731
732
- a tree with children `l,r` is associated with the Dyck word
733
described by ``usemap`` where `L` and `R` are respectively the
734
Dyck words associated with the trees `l` and `r`.
735
736
EXAMPLES::
737
738
sage: BinaryTree().to_dyck_word()
739
[]
740
sage: BinaryTree([]).to_dyck_word()
741
[1, 0]
742
sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word()
743
[1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0]
744
sage: BinaryTree([[None,[]],None]).to_dyck_word()
745
[1, 1, 0, 1, 0, 0]
746
sage: BinaryTree([[None,[]],None]).to_dyck_word("1R0L")
747
[1, 0, 1, 1, 0, 0]
748
sage: BinaryTree([[None,[]],None]).to_dyck_word("L1R0")
749
[1, 1, 0, 0, 1, 0]
750
sage: BinaryTree([[None,[]],None]).to_dyck_word("R1L0")
751
[1, 1, 0, 1, 0, 0]
752
sage: BinaryTree([[None,[]],None]).to_dyck_word("R10L")
753
Traceback (most recent call last):
754
...
755
ValueError: R10L is not a correct map
756
757
TESTS::
758
759
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
760
sage: bt == bt.to_dyck_word().to_binary_tree()
761
True
762
sage: bt == bt.to_dyck_word("1R0L").to_binary_tree("1R0L")
763
True
764
sage: bt == bt.to_dyck_word("L1R0").to_binary_tree("L1R0")
765
True
766
sage: bt == bt.to_dyck_word("R1L0").to_binary_tree("R1L0")
767
True
768
"""
769
from sage.combinat.dyck_word import DyckWord
770
if usemap not in ["1L0R", "1R0L", "L1R0", "R1L0"]:
771
raise ValueError, "%s is not a correct map"%(usemap)
772
return DyckWord(self._to_dyck_word_rec(usemap))
773
774
def _to_ordered_tree(self, bijection="left", root=None):
775
r"""
776
Internal recursive method to obtain an ordered tree from a binary
777
tree.
778
779
EXAMPLES::
780
781
sage: bt = BinaryTree([[],[]])
782
sage: bt._to_ordered_tree()
783
[[], [[]]]
784
sage: bt._to_ordered_tree(bijection="right")
785
[[[]], []]
786
sage: bt._to_ordered_tree(bijection="none")
787
Traceback (most recent call last):
788
...
789
ValueError: the bijection argument should be either left or right
790
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
791
sage: bt._to_ordered_tree()
792
[[], [[], []], [[], [[]]]]
793
sage: bt._to_ordered_tree(bijection="right")
794
[[[[]], [[]]], [[]], []]
795
"""
796
close_root = False
797
if(root is None):
798
from sage.combinat.ordered_tree import OrderedTree
799
root = OrderedTree().clone()
800
close_root = True
801
if(self):
802
left, right = self[0],self[1]
803
if(bijection == "left"):
804
root = left._to_ordered_tree(bijection=bijection,root=root)
805
root.append(right._to_ordered_tree(bijection=bijection,root=None))
806
elif(bijection =="right"):
807
root.append(left._to_ordered_tree(bijection=bijection, root=None))
808
root = right._to_ordered_tree(bijection=bijection,root=root)
809
else:
810
raise ValueError("the bijection argument should be either left or right")
811
if(close_root):
812
root.set_immutable()
813
return root
814
815
@combinatorial_map(name="To ordered tree, left child = left brother")
816
def to_ordered_tree_left_branch(self):
817
r"""
818
Return an ordered tree of size `n+1` by the following recursive rule:
819
820
- if `x` is the left child of `y`, `x` becomes the left brother
821
of `y`
822
- if `x` is the right child of `y`, `x` becomes the last child
823
of `y`
824
825
EXAMPLES::
826
827
sage: bt = BinaryTree([[],[]])
828
sage: bt.to_ordered_tree_left_branch()
829
[[], [[]]]
830
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
831
sage: bt.to_ordered_tree_left_branch()
832
[[], [[], []], [[], [[]]]]
833
"""
834
return self._to_ordered_tree()
835
836
@combinatorial_map(name="To ordered tree, right child = right brother")
837
def to_ordered_tree_right_branch(self):
838
r"""
839
Return an ordered tree of size `n+1` by the following recursive rule:
840
841
- if `x` is the right child of `y`, `x` becomes the right brother
842
of `y`
843
- if `x` is the left child of `y`, `x` becomes the first child
844
of `y`
845
846
EXAMPLES::
847
848
sage: bt = BinaryTree([[],[]])
849
sage: bt.to_ordered_tree_right_branch()
850
[[[]], []]
851
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
852
sage: bt.to_ordered_tree_right_branch()
853
[[[[]], [[]]], [[]], []]
854
"""
855
return self._to_ordered_tree(bijection="right")
856
857
def _postfix_word(self, left_first = True, start = 1):
858
r"""
859
Internal recursive method to obtain a postfix canonical read of the
860
binary tree.
861
862
EXAMPLES::
863
864
sage: bt = BinaryTree([[],[]])
865
sage: bt._postfix_word()
866
[1, 3, 2]
867
sage: bt._postfix_word(left_first=False)
868
[3, 1, 2]
869
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
870
sage: bt._postfix_word()
871
[1, 3, 4, 2, 6, 8, 7, 5]
872
sage: bt._postfix_word(left_first=False)
873
[8, 6, 7, 3, 4, 1, 2, 5]
874
"""
875
if not self:
876
return []
877
left = self[0]._postfix_word(left_first, start)
878
label = start + self[0].node_number()
879
right = self[1]._postfix_word(left_first, start = label +1)
880
if left_first:
881
left.extend(right)
882
left.append(label)
883
return left
884
else:
885
right.extend(left)
886
right.append(label)
887
return right
888
889
@combinatorial_map(name="To 312 avoiding permutation")
890
def to_312_avoiding_permutation(self):
891
r"""
892
Return a 312-avoiding permutation corresponding to the binary tree.
893
894
The linear extensions of a binary tree form an interval of the weak
895
order called the sylvester class of the tree. This permutation is
896
the minimal element of this sylvester class.
897
898
EXAMPLES::
899
900
sage: bt = BinaryTree([[],[]])
901
sage: bt.to_312_avoiding_permutation()
902
[1, 3, 2]
903
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
904
sage: bt.to_312_avoiding_permutation()
905
[1, 3, 4, 2, 6, 8, 7, 5]
906
907
TESTS::
908
909
sage: bt = BinaryTree([[],[]])
910
sage: bt == bt.to_312_avoiding_permutation().binary_search_tree_shape(left_to_right=False)
911
True
912
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
913
sage: bt == bt.to_312_avoiding_permutation().binary_search_tree_shape(left_to_right=False)
914
True
915
"""
916
from sage.combinat.permutation import Permutation
917
return Permutation(self._postfix_word())
918
919
@combinatorial_map(name="To complete tree")
920
def as_ordered_tree(self, with_leaves=True):
921
r"""
922
Return the same tree seen as an ordered tree. By default, leaves
923
are transformed into actual nodes, but this can be avoided by
924
setting the optional variable ``with_leaves`` to ``False``.
925
926
EXAMPLES::
927
928
sage: bt = BinaryTree([]); bt
929
[., .]
930
sage: bt.as_ordered_tree()
931
[[], []]
932
sage: bt.as_ordered_tree(with_leaves = False)
933
[]
934
sage: bt = bt.canonical_labelling(); bt
935
1[., .]
936
sage: bt.as_ordered_tree()
937
1[None[], None[]]
938
sage: bt.as_ordered_tree(with_leaves=False)
939
1[]
940
"""
941
if with_leaves:
942
children = [child.as_ordered_tree(with_leaves) for child in self]
943
else:
944
if not self:
945
raise ValueError("The empty binary tree cannot be made into an ordered tree with with_leaves = False")
946
children = [child.as_ordered_tree(with_leaves) for child in self if not child.is_empty()]
947
if self in LabelledBinaryTrees():
948
from sage.combinat.ordered_tree import LabelledOrderedTree
949
return LabelledOrderedTree(children, label = self.label())
950
else:
951
from sage.combinat.ordered_tree import OrderedTree
952
return OrderedTree(children)
953
954
@combinatorial_map(name="To graph")
955
def to_undirected_graph(self, with_leaves=False):
956
r"""
957
Return the undirected graph obtained from the tree nodes and edges.
958
959
Leaves are ignored by default, but one can set ``with_leaves`` to
960
``True`` to obtain the graph of the complete tree.
961
962
INPUT:
963
964
- ``with_leaves`` -- (default: ``False``) a Boolean, determining
965
whether the resulting graph will be formed from the leaves
966
and the nodes of ``self`` (if ``True``), or only from the
967
nodes of ``self`` (if ``False``)
968
969
EXAMPLES::
970
971
sage: bt = BinaryTree([])
972
sage: bt.to_undirected_graph()
973
Graph on 1 vertex
974
sage: bt.to_undirected_graph(with_leaves=True)
975
Graph on 3 vertices
976
977
sage: bt = BinaryTree()
978
sage: bt.to_undirected_graph()
979
Graph on 0 vertices
980
sage: bt.to_undirected_graph(with_leaves=True)
981
Graph on 1 vertex
982
983
If the tree is labelled, we use its labelling to label the graph.
984
Otherwise, we use the graph canonical labelling which means that
985
two different trees can have the same graph.
986
987
EXAMPLES::
988
989
sage: bt = BinaryTree([[],[None,[]]])
990
sage: bt.canonical_labelling()
991
2[1[., .], 3[., 4[., .]]]
992
sage: bt.canonical_labelling().to_undirected_graph().edges()
993
[(1, 2, None), (2, 3, None), (3, 4, None)]
994
sage: bt.to_undirected_graph().edges()
995
[(0, 3, None), (1, 2, None), (2, 3, None)]
996
sage: bt.canonical_labelling().to_undirected_graph() == bt.to_undirected_graph()
997
False
998
sage: BinaryTree([[],[]]).to_undirected_graph() == BinaryTree([[[],None],None]).to_undirected_graph()
999
True
1000
"""
1001
if (not with_leaves) and (not self):
1002
# this case needs extra care :(
1003
from sage.graphs.graph import Graph
1004
return Graph([])
1005
return self.as_ordered_tree(with_leaves).to_undirected_graph()
1006
1007
@combinatorial_map(name="To poset")
1008
def to_poset(self, with_leaves=False, root_to_leaf=False):
1009
r"""
1010
Return the poset obtained by interpreting the tree as a Hasse
1011
diagram.
1012
1013
The default orientation is from leaves to root but you can
1014
pass ``root_to_leaf=True`` to obtain the inverse orientation.
1015
1016
Leaves are ignored by default, but one can set ``with_leaves`` to
1017
``True`` to obtain the poset of the complete tree.
1018
1019
INPUT:
1020
1021
- ``with_leaves`` -- (default: ``False``) a Boolean, determining
1022
whether the resulting poset will be formed from the leaves
1023
and the nodes of ``self`` (if ``True``), or only from the
1024
nodes of ``self`` (if ``False``)
1025
- ``root_to_leaf`` -- (default: ``False``) a Boolean,
1026
determining whether the poset orientation should be from root
1027
to leaves (if ``True``) or from leaves to root (if ``False``).
1028
1029
EXAMPLES::
1030
1031
sage: bt = BinaryTree([])
1032
sage: bt.to_poset()
1033
Finite poset containing 1 elements
1034
sage: bt.to_poset(with_leaves=True)
1035
Finite poset containing 3 elements
1036
sage: bt.to_poset(with_leaves=True).cover_relations()
1037
[[0, 2], [1, 2]]
1038
sage: bt = BinaryTree([])
1039
sage: bt.to_poset(with_leaves=True,root_to_leaf=True).cover_relations()
1040
[[0, 1], [0, 2]]
1041
1042
If the tree is labelled, we use its labelling to label the poset.
1043
Otherwise, we use the poset canonical labelling::
1044
1045
sage: bt = BinaryTree([[],[None,[]]]).canonical_labelling()
1046
sage: bt
1047
2[1[., .], 3[., 4[., .]]]
1048
sage: bt.to_poset().cover_relations()
1049
[[4, 3], [3, 2], [1, 2]]
1050
1051
Let us check that the empty binary tree is correctly handled::
1052
1053
sage: bt = BinaryTree()
1054
sage: bt.to_poset()
1055
Finite poset containing 0 elements
1056
sage: bt.to_poset(with_leaves=True)
1057
Finite poset containing 1 elements
1058
"""
1059
if (not with_leaves) and (not self):
1060
# this case needs extra care :(
1061
from sage.combinat.posets.posets import Poset
1062
return Poset({})
1063
return self.as_ordered_tree(with_leaves).to_poset(root_to_leaf)
1064
1065
@combinatorial_map(name="To 132 avoiding permutation")
1066
def to_132_avoiding_permutation(self):
1067
r"""
1068
Return a 132-avoiding permutation corresponding to the binary tree.
1069
1070
The linear extensions of a binary tree form an interval of the weak
1071
order called the sylvester class of the tree. This permutation is
1072
the maximal element of this sylvester class.
1073
1074
EXAMPLES::
1075
1076
sage: bt = BinaryTree([[],[]])
1077
sage: bt.to_132_avoiding_permutation()
1078
[3, 1, 2]
1079
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
1080
sage: bt.to_132_avoiding_permutation()
1081
[8, 6, 7, 3, 4, 1, 2, 5]
1082
1083
TESTS::
1084
1085
sage: bt = BinaryTree([[],[]])
1086
sage: bt == bt.to_132_avoiding_permutation().binary_search_tree_shape(left_to_right=False)
1087
True
1088
sage: bt = BinaryTree([[[], [[], None]], [[], []]])
1089
sage: bt == bt.to_132_avoiding_permutation().binary_search_tree_shape(left_to_right=False)
1090
True
1091
"""
1092
from sage.combinat.permutation import Permutation
1093
return Permutation(self._postfix_word(left_first=False))
1094
1095
@combinatorial_map(order = 2, name="Left-right symmetry")
1096
def left_right_symmetry(self):
1097
r"""
1098
Return the left-right symmetrized tree of ``self``.
1099
1100
EXAMPLES::
1101
1102
sage: BinaryTree().left_right_symmetry()
1103
.
1104
sage: BinaryTree([]).left_right_symmetry()
1105
[., .]
1106
sage: BinaryTree([[],None]).left_right_symmetry()
1107
[., [., .]]
1108
sage: BinaryTree([[None, []],None]).left_right_symmetry()
1109
[., [[., .], .]]
1110
"""
1111
if not self:
1112
return BinaryTree()
1113
tree = [self[1].left_right_symmetry(),self[0].left_right_symmetry()]
1114
if(not self in LabelledBinaryTrees()):
1115
return BinaryTree(tree)
1116
return LabelledBinaryTree(tree, label = self.label())
1117
1118
@combinatorial_map(order=2, name="Left border symmetry")
1119
def left_border_symmetry(self):
1120
r"""
1121
Return the tree where a symmetry has been applied recursively on
1122
all left borders. If a tree is made of three trees `[T_1, T_2,
1123
T_3]` on its left border, it becomes `[T_3', T_2', T_1']` where
1124
same symmetry has been applied to `T_1, T_2, T_3`.
1125
1126
EXAMPLES::
1127
1128
sage: BinaryTree().left_border_symmetry()
1129
.
1130
sage: BinaryTree([]).left_border_symmetry()
1131
[., .]
1132
sage: BinaryTree([[None,[]],None]).left_border_symmetry()
1133
[[., .], [., .]]
1134
sage: BinaryTree([[None,[None,[]]],None]).left_border_symmetry()
1135
[[., .], [., [., .]]]
1136
sage: bt = BinaryTree([[None,[None,[]]],None]).canonical_labelling()
1137
sage: bt
1138
4[1[., 2[., 3[., .]]], .]
1139
sage: bt.left_border_symmetry()
1140
1[4[., .], 2[., 3[., .]]]
1141
"""
1142
if not self:
1143
return BinaryTree()
1144
border = []
1145
labelled = self in LabelledBinaryTrees()
1146
labels = []
1147
t = self
1148
while(t):
1149
border.append(t[1].left_border_symmetry())
1150
if labelled: labels.append(t.label())
1151
t = t[0]
1152
tree = BinaryTree()
1153
for r in border:
1154
if labelled:
1155
tree = LabelledBinaryTree([tree,r],label=labels.pop(0))
1156
else:
1157
tree = BinaryTree([tree,r])
1158
return tree
1159
1160
def canopee(self):
1161
"""
1162
Return the canopee of ``self``.
1163
1164
The *canopee* of a non-empty binary tree `T` with `n` internal nodes is
1165
the list `l` of `0` and `1` of length `n-1` obtained by going along the
1166
leaves of `T` from left to right except the two extremal ones, writing
1167
`0` if the leaf is a right leaf and `1` if the leaf is a left leaf.
1168
1169
EXAMPLES::
1170
1171
sage: BinaryTree([]).canopee()
1172
[]
1173
sage: BinaryTree([None, []]).canopee()
1174
[1]
1175
sage: BinaryTree([[], None]).canopee()
1176
[0]
1177
sage: BinaryTree([[], []]).canopee()
1178
[0, 1]
1179
sage: BinaryTree([[[], [[], None]], [[], []]]).canopee()
1180
[0, 1, 0, 0, 1, 0, 1]
1181
1182
The number of pairs `(t_1, t_2)` of binary trees of size `n` such that
1183
the canopee of `t_1` is the complementary of the canopee of `t_2` is
1184
also the number of Baxter permutations (see [DG94]_, see
1185
also :oeis:`A001181`). We check this in small cases::
1186
1187
sage: [len([(u,v) for u in BinaryTrees(n) for v in BinaryTrees(n)
1188
....: if map(lambda x:1-x, u.canopee()) == v.canopee()])
1189
....: for n in range(1, 5)]
1190
[1, 2, 6, 22]
1191
1192
Here is a less trivial implementation of this::
1193
1194
sage: from sage.sets.finite_set_map_cy import fibers
1195
sage: from sage.misc.all import attrcall
1196
sage: def baxter(n):
1197
....: f = fibers(lambda t: tuple(t.canopee()),
1198
....: BinaryTrees(n))
1199
....: return sum(len(f[i])*len(f[tuple(1-x for x in i)])
1200
....: for i in f)
1201
sage: [baxter(n) for n in range(1, 7)]
1202
[1, 2, 6, 22, 92, 422]
1203
1204
TESTS::
1205
1206
sage: t = BinaryTree().canopee()
1207
Traceback (most recent call last):
1208
...
1209
ValueError: canopee is only defined for non empty binary trees
1210
1211
REFERENCES:
1212
1213
.. [DG94] S. Dulucq and O. Guibert. Mots de piles, tableaux
1214
standards et permutations de Baxter, proceedings of
1215
Formal Power Series and Algebraic Combinatorics, 1994.
1216
"""
1217
if not self:
1218
raise ValueError("canopee is only defined for non empty binary trees")
1219
res = []
1220
def add_leaf_rec(tr):
1221
for i in range(2):
1222
if tr[i]:
1223
add_leaf_rec(tr[i])
1224
else:
1225
res.append(1-i)
1226
add_leaf_rec(self)
1227
return res[1:-1]
1228
1229
def in_order_traversal_iter(self):
1230
"""
1231
The depth-first infix-order traversal iterator for the binary
1232
tree ``self``.
1233
1234
This method iters each vertex (node and leaf alike) of the given
1235
binary tree following the depth-first infix order traversal
1236
algorithm.
1237
1238
The *depth-first infix order traversal algorithm* iterates
1239
through a binary tree as follows::
1240
1241
iterate through the left subtree (by the depth-first infix
1242
order traversal algorithm);
1243
yield the root;
1244
iterate through the right subtree (by the depth-first infix
1245
order traversal algorithm).
1246
1247
For example on the following binary tree `T`, where we denote
1248
leaves by `a, b, c, \ldots` and nodes by `1, 2, 3, \ldots`::
1249
1250
| ____3____ |
1251
| / \ |
1252
| 1 __7__ |
1253
| / \ / \ |
1254
| a 2 _5_ 8 |
1255
| / \ / \ / \ |
1256
| b c 4 6 h i |
1257
| / \ / \ |
1258
| d e f g |
1259
1260
the depth-first infix-order traversal algorithm iterates through
1261
the vertices of `T` in the following order:
1262
`a,1,b,2,c,3,d,4,e,5,f,6,g,7,h,8,i`.
1263
1264
See :meth:`in_order_traversal` for a version of this algorithm
1265
which not only iterates through, but actually does something at
1266
the vertices of tree.
1267
1268
TESTS::
1269
1270
sage: b = BinaryTree([[],[[],[]]]); ascii_art([b])
1271
[ _o_ ]
1272
[ / \ ]
1273
[ o o ]
1274
[ / \ ]
1275
[ o o ]
1276
sage: ascii_art(list(b.in_order_traversal_iter()))
1277
[ ]
1278
[ , o, , _o_ o o o ]
1279
[ / \ / \ ]
1280
[ o o o o ]
1281
[ / \ ]
1282
[ o o, , , , , , , ]
1283
sage: ascii_art(filter(lambda node: node.label() is not None,
1284
....: b.canonical_labelling().in_order_traversal_iter()))
1285
[ ]
1286
[ 1, _2_ 3 4 5 ]
1287
[ / \ / \ ]
1288
[ 1 4 3 5 ]
1289
[ / \ ]
1290
[ 3 5, , , ]
1291
1292
sage: list(BinaryTree(None).in_order_traversal_iter())
1293
[.]
1294
"""
1295
if self.is_empty():
1296
yield self
1297
return
1298
# TODO:: PYTHON 3
1299
# yield from self[0].in_order_traversal_iter()
1300
for left_subtree in self[0].in_order_traversal_iter():
1301
yield left_subtree
1302
yield self
1303
# TODO:: PYTHON 3
1304
# yield from self[1].in_order_traversal_iter()
1305
for right_subtree in self[1].in_order_traversal_iter():
1306
yield right_subtree
1307
1308
def in_order_traversal(self, node_action=None, leaf_action=None):
1309
r"""
1310
Explore the binary tree ``self`` using the depth-first infix-order
1311
traversal algorithm, executing the ``node_action`` function
1312
whenever traversing a node and executing the ``leaf_action``
1313
function whenever traversing a leaf.
1314
1315
In more detail, what this method does to a tree `T` is the
1316
following::
1317
1318
if the root of `T` is a node:
1319
apply in_order_traversal to the left subtree of `T`
1320
(with the same node_action and leaf_action);
1321
apply node_action to the root of `T`;
1322
apply in_order_traversal to the right subtree of `T`
1323
(with the same node_action and leaf_action);
1324
else:
1325
apply leaf_action to the root of `T`.
1326
1327
For example on the following binary tree `T`, where we denote
1328
leaves by `a, b, c, \ldots` and nodes by `1, 2, 3, \ldots`::
1329
1330
| ____3____ |
1331
| / \ |
1332
| 1 __7__ |
1333
| / \ / \ |
1334
| a 2 _5_ 8 |
1335
| / \ / \ / \ |
1336
| b c 4 6 h i |
1337
| / \ / \ |
1338
| d e f g |
1339
1340
this method first applies ``leaf_action`` to `a`, then applies
1341
``node_action`` to `1`, then ``leaf_action`` to `b`, then
1342
``node_action`` to `2`, etc., with the vertices being traversed
1343
in the order `a,1,b,2,c,3,d,4,e,5,f,6,g,7,h,8,i`.
1344
1345
See :meth:`in_order_traversal_iter` for a version of this
1346
algorithm which only iterates through the vertices rather than
1347
applying any function to them.
1348
1349
INPUT:
1350
1351
- ``node_action`` -- (optional) a function which takes a node in input
1352
and does something during the exploration
1353
- ``leaf_action`` -- (optional) a function which takes a leaf in input
1354
and does something during the exploration
1355
1356
TESTS::
1357
1358
sage: nb_leaf = 0
1359
sage: def l_action(_):
1360
....: global nb_leaf
1361
....: nb_leaf += 1
1362
sage: nb_node = 0
1363
sage: def n_action(_):
1364
....: global nb_node
1365
....: nb_node += 1
1366
1367
sage: BinaryTree().in_order_traversal(n_action, l_action)
1368
sage: nb_leaf, nb_node
1369
(1, 0)
1370
1371
sage: nb_leaf, nb_node = 0, 0
1372
sage: b = BinaryTree([[],[[],[]]]); b
1373
[[., .], [[., .], [., .]]]
1374
sage: b.in_order_traversal(n_action, l_action)
1375
sage: nb_leaf, nb_node
1376
(6, 5)
1377
sage: nb_leaf, nb_node = 0, 0
1378
sage: b = b.canonical_labelling()
1379
sage: b.in_order_traversal(n_action, l_action)
1380
sage: nb_leaf, nb_node
1381
(6, 5)
1382
sage: l = []
1383
sage: b.in_order_traversal(lambda node: l.append( node.label() ))
1384
sage: l
1385
[1, 2, 3, 4, 5]
1386
1387
sage: leaf = 'a'
1388
sage: l = []
1389
sage: def l_action(_):
1390
....: global leaf, l
1391
....: l.append(leaf)
1392
....: leaf = chr( ord(leaf)+1 )
1393
sage: n_action = lambda node: l.append( node.label() )
1394
sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).\
1395
....: canonical_labelling()
1396
sage: b.in_order_traversal(n_action, l_action)
1397
sage: l
1398
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 'g', 7, 'h', 8,
1399
'i']
1400
"""
1401
if leaf_action is None:
1402
leaf_action = lambda x: None
1403
if node_action is None:
1404
node_action = lambda x: None
1405
1406
for node in self.in_order_traversal_iter():
1407
if node.is_empty():
1408
leaf_action(node)
1409
else:
1410
node_action(node)
1411
1412
def tamari_greater(self):
1413
r"""
1414
The list of all trees greater or equal to ``self`` in the Tamari
1415
order.
1416
1417
This is the order filter of the Tamari order generated by ``self``.
1418
1419
The Tamari order on binary trees of size `n` is the partial order
1420
on the set of all binary trees of size `n` generated by the
1421
following requirement: If a binary tree `T'` is obtained by
1422
right rotation (see :meth:`right_rotate`) from a binary tree `T`,
1423
then `T < T'`.
1424
This not only is a well-defined partial order, but actually is
1425
a lattice structure on the set of binary trees of size `n`, and
1426
is a quotient of the weak order on the `n`-th symmetric group.
1427
See [CP12]_.
1428
1429
.. SEEALSO::
1430
1431
:meth:`tamari_smaller`
1432
1433
EXAMPLES:
1434
1435
For example, the tree::
1436
1437
| __o__ |
1438
| / \ |
1439
| o o |
1440
| / \ / |
1441
| o o o |
1442
1443
has these trees greater or equal to it::
1444
1445
|o , o , o , o , o , o ,|
1446
| \ \ \ \ \ \ |
1447
| o o o o _o_ __o__ |
1448
| \ \ \ \ / \ / \ |
1449
| o o o _o_ o o o o |
1450
| \ \ / \ / \ \ \ \ / |
1451
| o o o o o o o o o o |
1452
| \ \ \ / |
1453
| o o o o |
1454
| \ / |
1455
| o o |
1456
<BLANKLINE>
1457
| o , o , _o_ , _o__ , __o__ , ___o___ ,|
1458
| / \ / \ / \ / \ / \ / \ |
1459
| o o o o o o o _o_ o o o o |
1460
| \ \ / \ / \ \ \ \ / |
1461
| o o o o o o o o o o |
1462
| \ \ \ / \ \ |
1463
| o o o o o o |
1464
| \ / |
1465
| o o |
1466
<BLANKLINE>
1467
| _o_ , __o__ |
1468
| / \ / \ |
1469
| o o o o|
1470
| / \ \ / \ / |
1471
| o o o o o o |
1472
1473
TESTS::
1474
1475
sage: B = BinaryTree
1476
sage: b = B([None, B([None, B([None, B([])])])]);b
1477
[., [., [., [., .]]]]
1478
sage: b.tamari_greater()
1479
[[., [., [., [., .]]]]]
1480
sage: b = B([B([B([B([]), None]), None]), None]);b
1481
[[[[., .], .], .], .]
1482
sage: b.tamari_greater()
1483
[[., [., [., [., .]]]], [., [., [[., .], .]]],
1484
[., [[., .], [., .]]], [., [[., [., .]], .]],
1485
[., [[[., .], .], .]], [[., .], [., [., .]]],
1486
[[., .], [[., .], .]], [[., [., .]], [., .]],
1487
[[., [., [., .]]], .], [[., [[., .], .]], .],
1488
[[[., .], .], [., .]], [[[., .], [., .]], .],
1489
[[[., [., .]], .], .], [[[[., .], .], .], .]]
1490
"""
1491
from sage.combinat.tools import transitive_ideal
1492
return transitive_ideal(lambda x: x.tamari_succ(), self)
1493
1494
def tamari_pred(self):
1495
r"""
1496
Compute the list of predecessors of ``self`` in the Tamari poset.
1497
1498
This list is computed by performing all left rotates possible on
1499
its nodes.
1500
1501
EXAMPLES:
1502
1503
For this tree::
1504
1505
| __o__ |
1506
| / \ |
1507
| o o |
1508
| / \ / |
1509
| o o o |
1510
1511
the list is::
1512
1513
| o , _o_ |
1514
| / / \ |
1515
| _o_ o o |
1516
| / \ / / |
1517
| o o o o |
1518
| / \ / |
1519
| o o o |
1520
1521
TESTS::
1522
1523
sage: B = BinaryTree
1524
sage: b = B([B([B([B([]), None]), None]), None]);b
1525
[[[[., .], .], .], .]
1526
sage: b.tamari_pred()
1527
[]
1528
sage: b = B([None, B([None, B([None, B([])])])]);b
1529
[., [., [., [., .]]]]
1530
sage: b.tamari_pred()
1531
[[[., .], [., [., .]]], [., [[., .], [., .]]], [., [., [[., .], .]]]]
1532
"""
1533
res = []
1534
if self.is_empty():
1535
return []
1536
if not self[1].is_empty():
1537
res.append(self.left_rotate())
1538
B = self.parent()._element_constructor_
1539
return (res +
1540
[B([g, self[1]]) for g in self[0].tamari_pred()] +
1541
[B([self[0], d]) for d in self[1].tamari_pred()])
1542
1543
def tamari_smaller(self):
1544
r"""
1545
The list of all trees smaller or equal to ``self`` in the Tamari
1546
order.
1547
1548
This is the order ideal of the Tamari order generated by ``self``.
1549
1550
The Tamari order on binary trees of size `n` is the partial order
1551
on the set of all binary trees of size `n` generated by the
1552
following requirement: If a binary tree `T'` is obtained by
1553
right rotation (see :meth:`right_rotate`) from a binary tree `T`,
1554
then `T < T'`.
1555
This not only is a well-defined partial order, but actually is
1556
a lattice structure on the set of binary trees of size `n`, and
1557
is a quotient of the weak order on the `n`-th symmetric group.
1558
See [CP12]_.
1559
1560
.. SEEALSO::
1561
1562
:meth:`tamari_greater`
1563
1564
EXAMPLES:
1565
1566
The tree::
1567
1568
| __o__ |
1569
| / \ |
1570
| o o |
1571
| / \ / |
1572
| o o o |
1573
1574
has these trees smaller or equal to it::
1575
1576
| __o__ , _o_ , o , o, o, o |
1577
| / \ / \ / / / / |
1578
| o o o o _o_ o o o |
1579
| / \ / / / / \ / \ / / |
1580
|o o o o o o o o o o o |
1581
| / / \ / / / |
1582
| o o o o o o |
1583
| / / \ / |
1584
| o o o o |
1585
| / |
1586
| o |
1587
1588
TESTS::
1589
1590
sage: B = BinaryTree
1591
sage: b = B([None, B([None, B([None, B([])])])]);b
1592
[., [., [., [., .]]]]
1593
sage: b.tamari_smaller()
1594
[[., [., [., [., .]]]], [., [., [[., .], .]]],
1595
[., [[., .], [., .]]], [., [[., [., .]], .]],
1596
[., [[[., .], .], .]], [[., .], [., [., .]]],
1597
[[., .], [[., .], .]], [[., [., .]], [., .]],
1598
[[., [., [., .]]], .], [[., [[., .], .]], .],
1599
[[[., .], .], [., .]], [[[., .], [., .]], .],
1600
[[[., [., .]], .], .], [[[[., .], .], .], .]]
1601
sage: b = B([B([B([B([]), None]), None]), None]);b
1602
[[[[., .], .], .], .]
1603
sage: b.tamari_smaller()
1604
[[[[[., .], .], .], .]]
1605
"""
1606
from sage.combinat.tools import transitive_ideal
1607
return transitive_ideal(lambda x: x.tamari_pred(), self)
1608
1609
def tamari_succ(self):
1610
r"""
1611
Compute the list of successors of ``self`` in the Tamari poset.
1612
1613
This is the list of all trees obtained by a right rotate of
1614
one of its nodes.
1615
1616
EXAMPLES:
1617
1618
The list of successors of::
1619
1620
| __o__ |
1621
| / \ |
1622
| o o |
1623
| / \ / |
1624
| o o o |
1625
1626
is::
1627
1628
| _o__ , ___o___ , _o_ |
1629
| / \ / \ / \ |
1630
| o _o_ o o o o |
1631
| / \ \ / / \ \ |
1632
| o o o o o o o |
1633
| / \ |
1634
| o o |
1635
1636
TESTS::
1637
1638
sage: B = BinaryTree
1639
sage: b = B([B([B([B([]), None]), None]), None]);b
1640
[[[[., .], .], .], .]
1641
sage: b.tamari_succ()
1642
[[[[., .], .], [., .]], [[[., .], [., .]], .], [[[., [., .]], .], .]]
1643
1644
sage: b = B([])
1645
sage: b.tamari_succ()
1646
[]
1647
1648
sage: b = B([[],[]])
1649
sage: b.tamari_succ()
1650
[[., [., [., .]]]]
1651
"""
1652
res = []
1653
if self.is_empty():
1654
return []
1655
B = self.parent()._element_constructor_
1656
if not self[0].is_empty():
1657
res.append(self.right_rotate())
1658
return (res +
1659
[B([g, self[1]]) for g in self[0].tamari_succ()] +
1660
[B([self[0], d]) for d in self[1].tamari_succ()])
1661
1662
def q_hook_length_fraction(self, q=None, q_factor=False):
1663
r"""
1664
Compute the ``q``-hook length fraction of the binary tree ``self``,
1665
with an additional "q-factor" if desired.
1666
1667
If `T` is a (plane) binary tree and `q` is a polynomial
1668
indeterminate over some ring, then the `q`-hook length fraction
1669
`h_{q} (T)` of `T` is defined by
1670
1671
.. MATH::
1672
1673
h_{q} (T)
1674
= \frac{[\lvert T \rvert]_q!}{\prod_{t \in T}
1675
[\lvert T_t \rvert]_q},
1676
1677
where the product ranges over all nodes `t` of `T`, where `T_t`
1678
denotes the subtree of `T` consisting of `t` and its all
1679
descendants, and where for every tree `S`, we denote by
1680
`\lvert S \rvert` the number of nodes of `S`. While this
1681
definition only shows that `h_{q} (T)` is a rational function
1682
in `T`, it is in fact easy to show that `h_{q} (T)` is
1683
actually a polynomial in `T`, and thus makes sense when any
1684
element of a commutative ring is substituted for `q`.
1685
This can also be explicitly seen from the following recursive
1686
formula for `h_{q} (T)`:
1687
1688
.. MATH::
1689
1690
h_{q} (T)
1691
= \binom{ \lvert T \rvert - 1 }{ \lvert T_1 \rvert }_q
1692
h_{q} (T_1) h_{q} (T_2),
1693
1694
where `T` is any nonempty binary tree, and `T_1` and `T_2` are
1695
the two child trees of the root of `T`, and where
1696
`\binom{a}{b}_q` denotes a `q`-binomial coefficient.
1697
1698
A variation of the `q`-hook length fraction is the following
1699
"`q`-hook length fraction with `q`-factor":
1700
1701
.. MATH::
1702
1703
f_{q} (T)
1704
= h_{q} (T) \cdot
1705
\prod_{t \in T} q^{\lvert T_{\mathrm{right}(t)} \rvert},
1706
1707
where for every node `t`, we denote by `\mathrm{right}(t)` the
1708
right child of `t`.
1709
This `f_{q} (T)` differs from `h_{q} (T)` only in a
1710
multiplicative factor, which is a power of `q`.
1711
1712
When `q = 1`, both `f_{q} (T)` and `h_{q} (T)` equal the number
1713
of permutations whose binary search tree (see [HNT05]_ for the
1714
definition) is `T` (after dropping the labels). For example,
1715
there are `20` permutations which give a binary tree of the
1716
following shape::
1717
1718
| __o__ |
1719
| / \ |
1720
| o o |
1721
| / \ / |
1722
| o o o |
1723
1724
by the binary search insertion algorithm, in accordance with
1725
the fact that this tree satisfies `f_{1} (T) = 20`.
1726
1727
When `q` is considered as a polynomial indeterminate,
1728
`f_{q} (T)` is the generating function for all permutations
1729
whose binary search tree is `T` (after dropping the labels)
1730
with respect to the number of inversions (i. e., the Coxeter
1731
length) of the permutations.
1732
1733
Objects similar to `h_{q} (T)` also make sense for general
1734
ordered forests (rather than just binary trees), see e. g.
1735
[BW88]_, Theorem 9.1.
1736
1737
INPUT:
1738
1739
- ``q`` -- a ring element which is to be substituted as `q`
1740
into the `q`-hook length fraction (by default, this is
1741
set to be the indeterminate `q` in the polynomial ring
1742
`\ZZ[q]`)
1743
1744
- ``q_factor`` -- a Boolean (default: ``False``) which
1745
determines whether to compute `h_{q} (T)` or to
1746
compute `f_{q} (T)` (namely, `h_{q} (T)` is obtained when
1747
``q_factor == False``, and `f_{q} (T)` is obtained when
1748
``q_factor == True``)
1749
1750
REFERENCES:
1751
1752
.. [BW88] Anders Bjoerner, Michelle L. Wachs,
1753
*Generalized quotients in Coxeter groups*.
1754
Transactions of the American Mathematical Society,
1755
vol. 308, no. 1, July 1988.
1756
http://www.ams.org/journals/tran/1988-308-01/S0002-9947-1988-0946427-X/S0002-9947-1988-0946427-X.pdf
1757
1758
EXAMPLES:
1759
1760
Let us start with a simple example. Actually, let us start
1761
with the easiest possible example -- the binary tree with
1762
only one vertex (which is a leaf)::
1763
1764
sage: b = BinaryTree()
1765
sage: b.q_hook_length_fraction()
1766
1
1767
sage: b.q_hook_length_fraction(q_factor=True)
1768
1
1769
1770
Nothing different for a tree with one node and two leaves::
1771
1772
sage: b = BinaryTree([]); b
1773
[., .]
1774
sage: b.q_hook_length_fraction()
1775
1
1776
sage: b.q_hook_length_fraction(q_factor=True)
1777
1
1778
1779
Let us get to a more interesting tree::
1780
1781
sage: b = BinaryTree([[[],[]],[[],None]]); b
1782
[[[., .], [., .]], [[., .], .]]
1783
sage: b.q_hook_length_fraction()(q=1)
1784
20
1785
sage: b.q_hook_length_fraction()
1786
q^7 + 2*q^6 + 3*q^5 + 4*q^4 + 4*q^3 + 3*q^2 + 2*q + 1
1787
sage: b.q_hook_length_fraction(q_factor=True)
1788
q^10 + 2*q^9 + 3*q^8 + 4*q^7 + 4*q^6 + 3*q^5 + 2*q^4 + q^3
1789
sage: b.q_hook_length_fraction(q=2)
1790
465
1791
sage: b.q_hook_length_fraction(q=2, q_factor=True)
1792
3720
1793
sage: q = PolynomialRing(ZZ, 'q').gen()
1794
sage: b.q_hook_length_fraction(q=q**2)
1795
q^14 + 2*q^12 + 3*q^10 + 4*q^8 + 4*q^6 + 3*q^4 + 2*q^2 + 1
1796
1797
Let us check the fact that `f_{q} (T)` is the generating function
1798
for all permutations whose binary search tree is `T` (after
1799
dropping the labels) with respect to the number of inversions of
1800
the permutations::
1801
1802
sage: def q_hook_length_fraction_2(T):
1803
....: P = PolynomialRing(ZZ, 'q')
1804
....: q = P.gen()
1805
....: res = P.zero()
1806
....: for w in T.sylvester_class():
1807
....: res += q ** Permutation(w).length()
1808
....: return res
1809
sage: def test_genfun(i):
1810
....: return all( q_hook_length_fraction_2(T)
1811
....: == T.q_hook_length_fraction(q_factor=True)
1812
....: for T in BinaryTrees(i) )
1813
sage: test_genfun(4)
1814
True
1815
"""
1816
from sage.combinat.q_analogues import q_binomial
1817
1818
if q is None:
1819
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
1820
from sage.rings.integer_ring import ZZ
1821
basering = PolynomialRing(ZZ, 'q')
1822
q = basering.gen()
1823
else:
1824
basering = q.base_ring()
1825
1826
if q_factor:
1827
def product_of_subtrees(b):
1828
if b.is_empty():
1829
return basering.one()
1830
b0 = b[0]
1831
b1 = b[1]
1832
return q_binomial(b.node_number() - 1, b0.node_number(), q=q) * \
1833
product_of_subtrees(b0) * product_of_subtrees(b1) * \
1834
q ** (b1.node_number())
1835
else:
1836
def product_of_subtrees(b):
1837
if b.is_empty():
1838
return basering.one()
1839
b0 = b[0]
1840
b1 = b[1]
1841
return q_binomial(b.node_number() - 1, b0.node_number(), q=q) * \
1842
product_of_subtrees(b0) * product_of_subtrees(b1)
1843
1844
return product_of_subtrees(self)
1845
1846
@combinatorial_map(name="Right rotate")
1847
def right_rotate(self):
1848
r"""
1849
Return the result of right rotation applied to the binary
1850
tree ``self``.
1851
1852
Right rotation on binary trees is defined as follows:
1853
Let `T` be a binary tree such that the left child of the
1854
root of `T` is a node. Let `C` be the right
1855
child of the root of `T`, and let `A` and `B` be the
1856
left and right children of the left child of the root
1857
of `T`. (Keep in mind that nodes of trees are identified
1858
with the subtrees consisting of their descendants.)
1859
Then, the right rotation of `T` is the binary tree in
1860
which the left child of the root is `A`, whereas
1861
the right child of the root is a node whose left and right
1862
children are `B` and `C`. In pictures::
1863
1864
| * * |
1865
| / \ / \ |
1866
| * C -right-rotate-> A * |
1867
| / \ / \ |
1868
| A B B C |
1869
1870
where asterisks signify a single node each (but `A`, `B`
1871
and `C` might be empty).
1872
1873
For example, ::
1874
1875
| o _o_ |
1876
| / / \ |
1877
| o -right-rotate-> o o |
1878
| / \ / |
1879
| o o o |
1880
<BLANKLINE>
1881
| __o__ _o__ |
1882
| / \ / \ |
1883
| o o -right-rotate-> o _o_ |
1884
| / \ / / \ |
1885
| o o o o o |
1886
| / \ \ |
1887
| o o o |
1888
1889
Right rotation is the inverse operation to left rotation
1890
(:meth:`left_rotate`).
1891
1892
The right rotation operation introduced here is the one defined
1893
in Definition 2.1 of [CP12]_.
1894
1895
.. SEEALSO::
1896
1897
:meth:`left_rotate`
1898
1899
EXAMPLES::
1900
1901
sage: b = BinaryTree([[[],[]], None]); ascii_art([b])
1902
[ o ]
1903
[ / ]
1904
[ o ]
1905
[ / \ ]
1906
[ o o ]
1907
sage: ascii_art([b.right_rotate()])
1908
[ _o_ ]
1909
[ / \ ]
1910
[ o o ]
1911
[ / ]
1912
[ o ]
1913
sage: b = BinaryTree([[[[],None],[None,[]]], []]); ascii_art([b])
1914
[ __o__ ]
1915
[ / \ ]
1916
[ o o ]
1917
[ / \ ]
1918
[ o o ]
1919
[ / \ ]
1920
[ o o ]
1921
sage: ascii_art([b.right_rotate()])
1922
[ _o__ ]
1923
[ / \ ]
1924
[ o _o_ ]
1925
[ / / \ ]
1926
[ o o o ]
1927
[ \ ]
1928
[ o ]
1929
"""
1930
B = self.parent()._element_constructor_
1931
return B([self[0][0], B([self[0][1], self[1]])])
1932
1933
@combinatorial_map(name="Left rotate")
1934
def left_rotate(self):
1935
r"""
1936
Return the result of left rotation applied to the binary
1937
tree ``self``.
1938
1939
Left rotation on binary trees is defined as follows:
1940
Let `T` be a binary tree such that the right child of the
1941
root of `T` is a node. Let `A` be the left
1942
child of the root of `T`, and let `B` and `C` be the
1943
left and right children of the right child of the root
1944
of `T`. (Keep in mind that nodes of trees are identified
1945
with the subtrees consisting of their descendants.)
1946
Then, the left rotation of `T` is the binary tree in
1947
which the right child of the root is `C`, whereas
1948
the left child of the root is a node whose left and right
1949
children are `A` and `B`. In pictures::
1950
1951
| * * |
1952
| / \ / \ |
1953
| A * -left-rotate-> * C |
1954
| / \ / \ |
1955
| B C A B |
1956
1957
where asterisks signify a single node each (but `A`, `B`
1958
and `C` might be empty).
1959
1960
For example, ::
1961
1962
| _o_ o |
1963
| / \ / |
1964
| o o -left-rotate-> o |
1965
| / / \ |
1966
| o o o |
1967
<BLANKLINE>
1968
| __o__ o |
1969
| / \ / |
1970
| o o -left-rotate-> o |
1971
| / \ / |
1972
| o o o |
1973
| / \ / \ |
1974
| o o o o |
1975
| / \ |
1976
| o o |
1977
1978
Left rotation is the inverse operation to right rotation
1979
(:meth:`right_rotate`).
1980
1981
.. SEEALSO::
1982
1983
:meth:`right_rotate`
1984
1985
EXAMPLES::
1986
1987
sage: b = BinaryTree([[],[[],None]]); ascii_art([b])
1988
[ _o_ ]
1989
[ / \ ]
1990
[ o o ]
1991
[ / ]
1992
[ o ]
1993
sage: ascii_art([b.left_rotate()])
1994
[ o ]
1995
[ / ]
1996
[ o ]
1997
[ / \ ]
1998
[ o o ]
1999
sage: b.left_rotate().right_rotate() == b
2000
True
2001
"""
2002
B = self.parent()._element_constructor_
2003
return B([B([self[0], self[1][0]]), self[1][1]])
2004
2005
@combinatorial_map(name="Over operation on Binary Trees")
2006
def over(self, bt):
2007
r"""
2008
Return ``self`` over ``bt``, where "over" is the ``over``
2009
(`/`) operation.
2010
2011
If `T` and `T'` are two binary trees, then `T` over `T'`
2012
(written `T / T'`) is defined as the tree obtained by grafting
2013
`T'` on the rightmost leaf of `T`. More precisely, `T / T'` is
2014
defined by identifying the root of the `T'` with the rightmost
2015
leaf of `T`. See section 4.5 of [HNT05]_.
2016
2017
If `T` is empty, then `T / T' = T'`.
2018
2019
The definition of this "over" operation goes back to
2020
Loday-Ronco [LodRon0102066]_ (Definition 2.2), but it is
2021
denoted by `\backslash` and called the "under" operation there.
2022
In fact, trees in sage have their root at the top, contrary to
2023
the trees in [LodRon0102066]_ which are growing upwards. For
2024
this reason, the names of the over and under operations are
2025
swapped, in order to keep a graphical meaning.
2026
(Our notation follows that of section 4.5 of [HNT05]_.)
2027
2028
.. SEEALSO::
2029
2030
:meth:`under`
2031
2032
EXAMPLES:
2033
2034
Showing only the nodes of a binary tree, here is an
2035
example for the over operation::
2036
2037
| o __o__ _o_ |
2038
| / \ / / \ = / \ |
2039
| o o o o o o |
2040
| \ / \ |
2041
| o o __o__ |
2042
| / \ |
2043
| o o |
2044
| \ / |
2045
| o o |
2046
2047
A Sage example::
2048
2049
sage: b1 = BinaryTree([[],[[],[]]])
2050
sage: b2 = BinaryTree([[None, []],[]])
2051
sage: ascii_art((b1, b2, b1/b2))
2052
( _o_ _o_ _o_ )
2053
( / \ / \ / \ )
2054
( o o o o o o_ )
2055
( / \ \ / \ )
2056
( o o, o , o o )
2057
( \ )
2058
( _o_ )
2059
( / \ )
2060
( o o )
2061
( \ )
2062
( o )
2063
2064
TESTS::
2065
2066
sage: b1 = BinaryTree([[],[]]); ascii_art([b1])
2067
[ o ]
2068
[ / \ ]
2069
[ o o ]
2070
sage: b2 = BinaryTree([[None,[]],[[],None]]); ascii_art([b2])
2071
[ __o__ ]
2072
[ / \ ]
2073
[ o o ]
2074
[ \ / ]
2075
[ o o ]
2076
sage: ascii_art([b1.over(b2)])
2077
[ _o_ ]
2078
[ / \ ]
2079
[ o o ]
2080
[ \ ]
2081
[ __o__ ]
2082
[ / \ ]
2083
[ o o ]
2084
[ \ / ]
2085
[ o o ]
2086
2087
The same in the labelled case::
2088
2089
sage: b1 = b1.canonical_labelling()
2090
sage: b2 = b2.canonical_labelling()
2091
sage: ascii_art([b1.over(b2)])
2092
[ _2_ ]
2093
[ / \ ]
2094
[ 1 3 ]
2095
[ \ ]
2096
[ __3__ ]
2097
[ / \ ]
2098
[ 1 5 ]
2099
[ \ / ]
2100
[ 2 4 ]
2101
"""
2102
B = self.parent()._element_constructor_
2103
if self.is_empty():
2104
return bt
2105
if hasattr(self, "label"):
2106
lab = self.label()
2107
return B([self[0], self[1].over(bt)], lab)
2108
else:
2109
return B([self[0], self[1].over(bt)])
2110
2111
__div__ = over
2112
2113
@combinatorial_map(name="Under operation on Binary Trees")
2114
def under(self, bt):
2115
r"""
2116
Return ``self`` under ``bt``, where "under" is the ``under``
2117
(`\backslash`) operation.
2118
2119
If `T` and `T'` are two binary trees, then `T` under `T'`
2120
(written `T \backslash T'`) is defined as the tree obtained
2121
by grafting `T` on the leftmost leaf of `T'`. More precisely,
2122
`T \backslash T'` is defined by identifying the root of `T`
2123
with the leftmost leaf of `T'`.
2124
2125
If `T'` is empty, then `T \backslash T' = T`.
2126
2127
The definition of this "under" operation goes back to
2128
Loday-Ronco [LodRon0102066]_ (Definition 2.2), but it is
2129
denoted by `/` and called the "over" operation there. In fact,
2130
trees in sage have their root at the top, contrary to the trees
2131
in [LodRon0102066]_ which are growing upwards. For this reason,
2132
the names of the over and under operations are swapped, in
2133
order to keep a graphical meaning.
2134
(Our notation follows that of section 4.5 of [HNT05]_.)
2135
2136
.. SEEALSO::
2137
2138
:meth:`over`
2139
2140
EXAMPLES:
2141
2142
Showing only the nodes of a binary tree, here is an
2143
example for the under operation::
2144
2145
sage: b1 = BinaryTree([[],[]])
2146
sage: b2 = BinaryTree([None,[]])
2147
sage: ascii_art((b1, b2, b1 \ b2))
2148
( o o _o_ )
2149
( / \ \ / \ )
2150
( o o, o, o o )
2151
( / \ )
2152
( o o )
2153
2154
TESTS::
2155
2156
sage: b1 = BinaryTree([[],[[None,[]],None]]); ascii_art([b1])
2157
[ _o_ ]
2158
[ / \ ]
2159
[ o o ]
2160
[ / ]
2161
[ o ]
2162
[ \ ]
2163
[ o ]
2164
sage: b2 = BinaryTree([[],[None,[]]]); ascii_art([b2])
2165
[ o ]
2166
[ / \ ]
2167
[ o o ]
2168
[ \ ]
2169
[ o ]
2170
sage: ascii_art([b1.under(b2)])
2171
[ o_ ]
2172
[ / \ ]
2173
[ o o ]
2174
[ / \ ]
2175
[ _o_ o ]
2176
[ / \ ]
2177
[ o o ]
2178
[ / ]
2179
[ o ]
2180
[ \ ]
2181
[ o ]
2182
2183
The same in the labelled case::
2184
2185
sage: b1 = b1.canonical_labelling()
2186
sage: b2 = b2.canonical_labelling()
2187
sage: ascii_art([b1.under(b2)])
2188
[ 2_ ]
2189
[ / \ ]
2190
[ 1 3 ]
2191
[ / \ ]
2192
[ _2_ 4 ]
2193
[ / \ ]
2194
[ 1 5 ]
2195
[ / ]
2196
[ 3 ]
2197
[ \ ]
2198
[ 4 ]
2199
"""
2200
B = self.parent()._element_constructor_
2201
if bt.is_empty():
2202
return self
2203
lab = None
2204
if hasattr(bt, "label"):
2205
lab = bt.label()
2206
return B([self.under(bt[0]), bt[1]], lab)
2207
else:
2208
return B([self.under(bt[0]), bt[1]])
2209
2210
_backslash_ = under
2211
2212
def sylvester_class(self, left_to_right=False):
2213
r"""
2214
Iterate over the sylvester class corresponding to the binary tree
2215
``self``.
2216
2217
The sylvester class of a tree `T` is the set of permutations
2218
`\sigma` whose binary search tree (a notion defined in [HNT05]_,
2219
Definition 7) is `T` after forgetting the labels. This is an
2220
equivalence class of the sylvester congruence (the congruence on
2221
words which holds two words `uacvbw` and `ucavbw` congruent
2222
whenever `a`, `b`, `c` are letters satisfying `a \leq b < c`, and
2223
extends by transitivity) on the symmetric group.
2224
2225
For example the following tree's sylvester class consists of the
2226
permutations `(1,3,2)` and `(3,1,2)`::
2227
2228
[ o ]
2229
[ / \ ]
2230
[ o o ]
2231
2232
(only the nodes are drawn here).
2233
2234
The binary search tree of a word is constructed by an RSK-like
2235
insertion algorithm which proceeds as follows: Start with an
2236
empty labelled binary tree, and read the word from left to right.
2237
Each time a letter is read from the word, insert this letter in
2238
the existing tree using binary search tree insertion
2239
(:meth:`~sage.combinat.binary_tree.LabelledBinaryTree.binary_search_insert`).
2240
If a left-to-right reading is to be employed instead, the
2241
``left_to_right`` optional keyword variable should be set to
2242
``True``.
2243
2244
TESTS::
2245
2246
sage: list(BinaryTree([[],[]]).sylvester_class())
2247
[[1, 3, 2], [3, 1, 2]]
2248
sage: bt = BinaryTree([[[],None],[[],[]]])
2249
sage: l = list(bt.sylvester_class()); l
2250
[[1, 2, 4, 6, 5, 3],
2251
[1, 4, 2, 6, 5, 3],
2252
[1, 4, 6, 2, 5, 3],
2253
[1, 4, 6, 5, 2, 3],
2254
[4, 1, 2, 6, 5, 3],
2255
[4, 1, 6, 2, 5, 3],
2256
[4, 1, 6, 5, 2, 3],
2257
[4, 6, 1, 2, 5, 3],
2258
[4, 6, 1, 5, 2, 3],
2259
[4, 6, 5, 1, 2, 3],
2260
[1, 2, 6, 4, 5, 3],
2261
[1, 6, 2, 4, 5, 3],
2262
[1, 6, 4, 2, 5, 3],
2263
[1, 6, 4, 5, 2, 3],
2264
[6, 1, 2, 4, 5, 3],
2265
[6, 1, 4, 2, 5, 3],
2266
[6, 1, 4, 5, 2, 3],
2267
[6, 4, 1, 2, 5, 3],
2268
[6, 4, 1, 5, 2, 3],
2269
[6, 4, 5, 1, 2, 3]]
2270
sage: len(l) == Integer(bt.q_hook_length_fraction()(q=1))
2271
True
2272
2273
Border cases::
2274
2275
sage: list(BinaryTree().sylvester_class())
2276
[[]]
2277
sage: list(BinaryTree([]).sylvester_class())
2278
[[1]]
2279
"""
2280
if self.is_empty():
2281
yield []
2282
return
2283
from itertools import product
2284
from sage.combinat.words.word import Word as W
2285
from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 \
2286
as shuffle
2287
2288
if left_to_right:
2289
builder = lambda i, p: [i] + list(p)
2290
else:
2291
builder = lambda i, p: list(p) + [i]
2292
2293
shift = self[0].node_number() + 1
2294
for l, r in product(self[0].sylvester_class(),
2295
self[1].sylvester_class()):
2296
for p in shuffle(W(l), W([shift + ri for ri in r])):
2297
yield builder(shift, p)
2298
2299
def is_full(self):
2300
r"""
2301
Return ``True`` if ``self`` is full, else return ``False``.
2302
2303
A full binary tree is a tree in which every node either has two
2304
child nodes or has two child leaves.
2305
2306
This is also known as *proper binary tree* or *2-tree* or *strictly
2307
binary tree*.
2308
2309
For example::
2310
2311
| __o__ |
2312
| / \ |
2313
| o o |
2314
| / \ |
2315
| o o |
2316
| / \ |
2317
| o o |
2318
2319
is not full but the next one is::
2320
2321
| ___o___ |
2322
| / \ |
2323
| __o__ o |
2324
| / \ |
2325
| o o |
2326
| / \ / \ |
2327
| o o o o |
2328
2329
EXAMPLES::
2330
2331
sage: BinaryTree([[[[],None],[None,[]]], []]).is_full()
2332
False
2333
sage: BinaryTree([[[[],[]],[[],[]]], []]).is_full()
2334
True
2335
sage: ascii_art(filter(lambda bt: bt.is_full(), BinaryTrees(5)))
2336
[ _o_ _o_ ]
2337
[ / \ / \ ]
2338
[ o o o o ]
2339
[ / \ / \ ]
2340
[ o o, o o ]
2341
"""
2342
if self.is_empty():
2343
return True
2344
if self[0].is_empty() != self[1].is_empty():
2345
return False
2346
return self[0].is_full() and self[1].is_full()
2347
2348
def is_perfect(self):
2349
r"""
2350
Return ``True`` if ``self`` is perfect, else return ``False``.
2351
2352
A perfect binary tree is a full tree in which all leaves are at the
2353
same depth.
2354
2355
For example::
2356
2357
| ___o___ |
2358
| / \ |
2359
| __o__ o |
2360
| / \ |
2361
| o o |
2362
| / \ / \ |
2363
| o o o o |
2364
2365
is not perfect but the next one is::
2366
2367
| __o__ |
2368
| / \ |
2369
| o o |
2370
| / \ / \ |
2371
| o o o o |
2372
2373
EXAMPLES::
2374
2375
sage: lst = lambda i: filter(lambda bt: bt.is_perfect(), BinaryTrees(i))
2376
sage: for i in range(10): ascii_art(lst(i)) # long time
2377
[ ]
2378
[ o ]
2379
[ ]
2380
[ o ]
2381
[ / \ ]
2382
[ o o ]
2383
[ ]
2384
[ ]
2385
[ ]
2386
[ __o__ ]
2387
[ / \ ]
2388
[ o o ]
2389
[ / \ / \ ]
2390
[ o o o o ]
2391
[ ]
2392
[ ]
2393
"""
2394
return 2 ** self.depth() - 1 == self.node_number()
2395
2396
def is_complete(self):
2397
r"""
2398
Return ``True`` if ``self`` is complete, else return ``False``.
2399
2400
In a nutshell, a complete binary tree is a perfect binary tree
2401
except possibly in the last level, with all nodes in the last
2402
level "flush to the left".
2403
2404
In more detail:
2405
A complete binary tree (also called binary heap) is a binary tree in
2406
which every level, except possibly the last one (the deepest), is
2407
completely filled. At depth `n`, all nodes must be as far left as
2408
possible.
2409
2410
For example::
2411
2412
| ___o___ |
2413
| / \ |
2414
| __o__ o |
2415
| / \ |
2416
| o o |
2417
| / \ / \ |
2418
| o o o o |
2419
2420
is not complete but the following ones are::
2421
2422
| __o__ _o_ ___o___ |
2423
| / \ / \ / \ |
2424
| o o o o __o__ o |
2425
| / \ / \ / \ / \ / \ |
2426
| o o o o, o o , o o o o |
2427
| / \ / |
2428
| o o o |
2429
2430
EXAMPLES::
2431
2432
sage: lst = lambda i: filter(lambda bt: bt.is_complete(), BinaryTrees(i))
2433
sage: for i in range(9): ascii_art(lst(i)) # long time
2434
[ ]
2435
[ o ]
2436
[ o ]
2437
[ / ]
2438
[ o ]
2439
[ o ]
2440
[ / \ ]
2441
[ o o ]
2442
[ o ]
2443
[ / \ ]
2444
[ o o ]
2445
[ / ]
2446
[ o ]
2447
[ _o_ ]
2448
[ / \ ]
2449
[ o o ]
2450
[ / \ ]
2451
[ o o ]
2452
[ __o__ ]
2453
[ / \ ]
2454
[ o o ]
2455
[ / \ / ]
2456
[ o o o ]
2457
[ __o__ ]
2458
[ / \ ]
2459
[ o o ]
2460
[ / \ / \ ]
2461
[ o o o o ]
2462
[ __o__ ]
2463
[ / \ ]
2464
[ o o ]
2465
[ / \ / \ ]
2466
[ o o o o ]
2467
[ / ]
2468
[ o ]
2469
"""
2470
if self.is_empty():
2471
return True
2472
# self := L ^ R
2473
dL = self[0].depth()
2474
dR = self[1].depth()
2475
# if L is perfect
2476
if self[0].is_perfect():
2477
# if the depth of R == depth of L then R must be complete
2478
if dL == dR:
2479
return self[1].is_complete()
2480
# else R is perfect with depth equals depth of L - 1
2481
elif dL == dR + 1:
2482
return self[1].is_perfect()
2483
return False
2484
# L is not perfect then R is perfect and the depth of L = the depth of
2485
# R + 1
2486
return self[0].is_complete() and self[1].is_perfect() and dL == dR + 1
2487
2488
from sage.structure.parent import Parent
2489
from sage.structure.unique_representation import UniqueRepresentation
2490
from sage.misc.classcall_metaclass import ClasscallMetaclass
2491
2492
from sage.sets.non_negative_integers import NonNegativeIntegers
2493
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
2494
from sage.sets.family import Family
2495
from sage.misc.cachefunc import cached_method
2496
2497
2498
# Abstract class to serve as a Factory no instance are created.
2499
class BinaryTrees(UniqueRepresentation, Parent):
2500
"""
2501
Factory for binary trees.
2502
2503
INPUT:
2504
2505
- ``size`` -- (optional) an integer
2506
2507
OUPUT:
2508
2509
- the set of all binary trees (of the given ``size`` if specified)
2510
2511
EXAMPLES::
2512
2513
sage: BinaryTrees()
2514
Binary trees
2515
2516
sage: BinaryTrees(2)
2517
Binary trees of size 2
2518
2519
.. NOTE:: this is a factory class whose constructor returns instances of
2520
subclasses.
2521
2522
.. NOTE:: the fact that BinaryTrees is a class instead of a simple callable
2523
is an implementation detail. It could be changed in the future
2524
and one should not rely on it.
2525
"""
2526
@staticmethod
2527
def __classcall_private__(cls, n=None):
2528
"""
2529
TESTS::
2530
2531
sage: from sage.combinat.binary_tree import BinaryTrees_all, BinaryTrees_size
2532
sage: isinstance(BinaryTrees(2), BinaryTrees)
2533
True
2534
sage: isinstance(BinaryTrees(), BinaryTrees)
2535
True
2536
sage: BinaryTrees(2) is BinaryTrees_size(2)
2537
True
2538
sage: BinaryTrees(5).cardinality()
2539
42
2540
sage: BinaryTrees() is BinaryTrees_all()
2541
True
2542
"""
2543
if n is None:
2544
return BinaryTrees_all()
2545
else:
2546
if not (isinstance(n, (Integer, int)) and n >= 0):
2547
raise ValueError("n must be a nonnegative integer")
2548
return BinaryTrees_size(Integer(n))
2549
2550
@cached_method
2551
def leaf(self):
2552
"""
2553
Return a leaf tree with ``self`` as parent.
2554
2555
EXAMPLES::
2556
2557
sage: BinaryTrees().leaf()
2558
.
2559
2560
TEST::
2561
2562
sage: (BinaryTrees().leaf() is
2563
....: sage.combinat.binary_tree.BinaryTrees_all().leaf())
2564
True
2565
"""
2566
return self(None)
2567
2568
#################################################################
2569
# Enumerated set of all binary trees
2570
#################################################################
2571
class BinaryTrees_all(DisjointUnionEnumeratedSets, BinaryTrees):
2572
2573
def __init__(self):
2574
"""
2575
TESTS::
2576
2577
sage: from sage.combinat.binary_tree import BinaryTrees_all
2578
sage: B = BinaryTrees_all()
2579
sage: B.cardinality()
2580
+Infinity
2581
2582
sage: it = iter(B)
2583
sage: (it.next(), it.next(), it.next(), it.next(), it.next())
2584
(., [., .], [., [., .]], [[., .], .], [., [., [., .]]])
2585
sage: it.next().parent()
2586
Binary trees
2587
sage: B([])
2588
[., .]
2589
2590
sage: B is BinaryTrees_all()
2591
True
2592
sage: TestSuite(B).run() # long time
2593
"""
2594
DisjointUnionEnumeratedSets.__init__(
2595
self, Family(NonNegativeIntegers(), BinaryTrees_size),
2596
facade=True, keepkey = False)
2597
2598
def _repr_(self):
2599
"""
2600
TEST::
2601
2602
sage: BinaryTrees() # indirect doctest
2603
Binary trees
2604
"""
2605
return "Binary trees"
2606
2607
def __contains__(self, x):
2608
"""
2609
TESTS::
2610
2611
sage: S = BinaryTrees()
2612
sage: 1 in S
2613
False
2614
sage: S([]) in S
2615
True
2616
"""
2617
return isinstance(x, self.element_class)
2618
2619
def __call__(self, x=None, *args, **keywords):
2620
"""
2621
Ensure that ``None`` instead of ``0`` is passed by default.
2622
2623
TESTS::
2624
2625
sage: B = BinaryTrees()
2626
sage: B()
2627
.
2628
"""
2629
return super(BinaryTrees, self).__call__(x, *args, **keywords)
2630
2631
def unlabelled_trees(self):
2632
"""
2633
Return the set of unlabelled trees associated to ``self``.
2634
2635
EXAMPLES::
2636
2637
sage: BinaryTrees().unlabelled_trees()
2638
Binary trees
2639
"""
2640
return self
2641
2642
def labelled_trees(self):
2643
"""
2644
Return the set of labelled trees associated to ``self``.
2645
2646
EXAMPLES::
2647
2648
sage: BinaryTrees().labelled_trees()
2649
Labelled binary trees
2650
"""
2651
return LabelledBinaryTrees()
2652
2653
def _element_constructor_(self, *args, **keywords):
2654
"""
2655
EXAMPLES::
2656
2657
sage: B = BinaryTrees()
2658
sage: B._element_constructor_([])
2659
[., .]
2660
sage: B([[],[]]) # indirect doctest
2661
[[., .], [., .]]
2662
sage: B(None) # indirect doctest
2663
.
2664
"""
2665
return self.element_class(self, *args, **keywords)
2666
2667
Element = BinaryTree
2668
2669
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
2670
#################################################################
2671
# Enumerated set of binary trees of a given size
2672
#################################################################
2673
class BinaryTrees_size(BinaryTrees):
2674
"""
2675
The enumerated sets of binary trees of given size
2676
2677
TESTS::
2678
2679
sage: from sage.combinat.binary_tree import BinaryTrees_size
2680
sage: for i in range(6): TestSuite(BinaryTrees_size(i)).run()
2681
"""
2682
def __init__(self, size):
2683
"""
2684
TESTS::
2685
2686
sage: S = BinaryTrees(3)
2687
sage: S == loads(dumps(S))
2688
True
2689
2690
sage: S is BinaryTrees(3)
2691
True
2692
"""
2693
super(BinaryTrees_size, self).__init__(category = FiniteEnumeratedSets())
2694
self._size = size
2695
2696
def _repr_(self):
2697
"""
2698
TESTS::
2699
2700
sage: BinaryTrees(3) # indirect doctest
2701
Binary trees of size 3
2702
"""
2703
return "Binary trees of size %s"%(self._size)
2704
2705
def __contains__(self, x):
2706
"""
2707
TESTS::
2708
2709
sage: S = BinaryTrees(3)
2710
sage: 1 in S
2711
False
2712
sage: S([[],[]]) in S
2713
True
2714
"""
2715
return isinstance(x, self.element_class) and x.node_number() == self._size
2716
2717
def _an_element_(self):
2718
"""
2719
TESTS::
2720
2721
sage: BinaryTrees(0).an_element() # indirect doctest
2722
.
2723
"""
2724
return self.first()
2725
2726
def cardinality(self):
2727
"""
2728
The cardinality of ``self``
2729
2730
This is a Catalan number.
2731
2732
TESTS::
2733
2734
sage: BinaryTrees(0).cardinality()
2735
1
2736
sage: BinaryTrees(5).cardinality()
2737
42
2738
"""
2739
from combinat import catalan_number
2740
return catalan_number(self._size)
2741
2742
def __iter__(self):
2743
"""
2744
A basic generator.
2745
2746
.. TODO:: could be optimized.
2747
2748
TESTS::
2749
2750
sage: BinaryTrees(0).list()
2751
[.]
2752
sage: BinaryTrees(1).list()
2753
[[., .]]
2754
sage: BinaryTrees(3).list()
2755
[[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]]
2756
"""
2757
if self._size == 0:
2758
yield self._element_constructor_()
2759
else:
2760
for i in range(0, self._size):
2761
for lft in self.__class__(i):
2762
for rgt in self.__class__(self._size-1-i):
2763
yield self._element_constructor_([lft, rgt])
2764
2765
@lazy_attribute
2766
def _parent_for(self):
2767
"""
2768
The parent of the elements generated by ``self``.
2769
2770
TESTS::
2771
2772
sage: S = BinaryTrees(3)
2773
sage: S._parent_for
2774
Binary trees
2775
"""
2776
return BinaryTrees_all()
2777
2778
@lazy_attribute
2779
def element_class(self):
2780
"""
2781
TESTS::
2782
2783
sage: S = BinaryTrees(3)
2784
sage: S.element_class
2785
<class 'sage.combinat.binary_tree.BinaryTrees_all_with_category.element_class'>
2786
sage: S.first().__class__ == BinaryTrees().first().__class__
2787
True
2788
"""
2789
return self._parent_for.element_class
2790
2791
def _element_constructor_(self, *args, **keywords):
2792
"""
2793
EXAMPLES::
2794
2795
sage: S = BinaryTrees(0)
2796
sage: S([]) # indirect doctest
2797
Traceback (most recent call last):
2798
...
2799
ValueError: wrong number of nodes
2800
sage: S(None) # indirect doctest
2801
.
2802
2803
sage: S = BinaryTrees(1) # indirect doctest
2804
sage: S([])
2805
[., .]
2806
"""
2807
res = self.element_class(self._parent_for, *args, **keywords)
2808
if res.node_number() != self._size:
2809
raise ValueError("wrong number of nodes")
2810
return res
2811
2812
2813
2814
class LabelledBinaryTree(AbstractLabelledClonableTree, BinaryTree):
2815
"""
2816
Labelled binary trees.
2817
2818
A labelled binary tree is a binary tree (see :class:`BinaryTree` for
2819
the meaning of this) with a label assigned to each node.
2820
The labels need not be integers, nor are they required to be distinct.
2821
``None`` can be used as a label.
2822
2823
.. WARNING::
2824
2825
While it is possible to assign values to leaves (not just nodes)
2826
using this class, these labels are disregarded by various
2827
methods such as
2828
:meth:`~sage.combinat.abstract_tree.AbstractLabelledTree.labels`,
2829
:meth:`~sage.combinat.abstract_tree.AbstractLabelledTree.map_labels`,
2830
and (ironically)
2831
:meth:`~sage.combinat.abstract_tree.AbstractLabelledTree.leaf_labels`.
2832
2833
INPUT:
2834
2835
- ``children`` -- ``None`` (default) or a list, tuple or iterable of
2836
length `2` of labelled binary trees or convertible objects. This
2837
corresponds to the standard recursive definition of a labelled
2838
binary tree as being either a leaf, or a pair of:
2839
2840
- a pair of labelled binary trees,
2841
- and a label.
2842
2843
(The label is specified in the keyword variable ``label``; see
2844
below.)
2845
2846
Syntactic sugar allows leaving out all but the outermost calls
2847
of the ``LabelledBinaryTree()`` constructor, so that, e. g.,
2848
``LabelledBinaryTree([LabelledBinaryTree(None),LabelledBinaryTree(None)])``
2849
can be shortened to ``LabelledBinaryTree([None,None])``. However,
2850
using this shorthand, it is impossible to label any vertex of
2851
the tree other than the root (because there is no way to pass a
2852
``label`` variable without calling ``LabelledBinaryTree``
2853
explicitly).
2854
2855
It is also allowed to abbreviate ``[None, None]`` by ``[]`` if
2856
one does not want to label the leaves (which one should not do
2857
anyway!).
2858
2859
- ``label`` -- (default: ``None``) the label to be put on the root
2860
of this tree.
2861
2862
- ``check`` -- (default: ``True``) whether checks should be
2863
performed or not.
2864
2865
.. TODO::
2866
2867
It is currently not possible to use ``LabelledBinaryTree()``
2868
as a shorthand for ``LabelledBinaryTree(None)`` (in analogy to
2869
similar syntax in the ``BinaryTree`` class).
2870
2871
EXAMPLES::
2872
2873
sage: LabelledBinaryTree(None)
2874
.
2875
sage: LabelledBinaryTree(None, label="ae") # not well supported
2876
'ae'
2877
sage: LabelledBinaryTree([])
2878
None[., .]
2879
sage: LabelledBinaryTree([], label=3) # not well supported
2880
3[., .]
2881
sage: LabelledBinaryTree([None, None])
2882
None[., .]
2883
sage: LabelledBinaryTree([None, None], label=5)
2884
5[., .]
2885
sage: LabelledBinaryTree([None, []])
2886
None[., None[., .]]
2887
sage: LabelledBinaryTree([None, []], label=4)
2888
4[., None[., .]]
2889
sage: LabelledBinaryTree([[], None])
2890
None[None[., .], .]
2891
sage: LabelledBinaryTree("[[], .]", label=False)
2892
False[None[., .], .]
2893
sage: LabelledBinaryTree([None, LabelledBinaryTree([None, None], label=4)], label=3)
2894
3[., 4[., .]]
2895
sage: LabelledBinaryTree([None, BinaryTree([None, None])], label=3)
2896
3[., None[., .]]
2897
2898
sage: LabelledBinaryTree([[], None, []])
2899
Traceback (most recent call last):
2900
...
2901
ValueError: this is not a binary tree
2902
2903
sage: LBT = LabelledBinaryTree
2904
sage: t1 = LBT([[LBT([], label=2), None], None], label=4); t1
2905
4[None[2[., .], .], .]
2906
2907
TESTS::
2908
2909
sage: t1 = LabelledBinaryTree([[None, [[],[[], None]]],[[],[]]])
2910
sage: t2 = LabelledBinaryTree([[[],[]],[]])
2911
sage: with t1.clone() as t1c:
2912
....: t1c[1,1,1] = t2
2913
sage: t1 == t1c
2914
False
2915
"""
2916
__metaclass__ = ClasscallMetaclass
2917
2918
@staticmethod
2919
def __classcall_private__(cls, *args, **opts):
2920
"""
2921
Ensure that trees created by the sets and directly are the same and
2922
that they are instances of :class:`LabelledTree`.
2923
2924
TESTS::
2925
2926
sage: issubclass(LabelledBinaryTrees().element_class, LabelledBinaryTree)
2927
True
2928
sage: t0 = LabelledBinaryTree([[],[[], None]], label = 3)
2929
sage: t0.parent()
2930
Labelled binary trees
2931
sage: type(t0)
2932
<class 'sage.combinat.binary_tree.LabelledBinaryTrees_with_category.element_class'>
2933
"""
2934
return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
2935
2936
@lazy_class_attribute
2937
def _auto_parent(cls):
2938
"""
2939
The automatic parent of the elements of this class.
2940
2941
When calling the constructor of an element of this class, one needs a
2942
parent. This class attribute specifies which parent is used.
2943
2944
EXAMPLES::
2945
2946
sage: LabelledBinaryTree._auto_parent
2947
Labelled binary trees
2948
sage: LabelledBinaryTree([], label = 3).parent()
2949
Labelled binary trees
2950
"""
2951
return LabelledBinaryTrees()
2952
2953
def _repr_(self):
2954
"""
2955
TESTS::
2956
2957
sage: LBT = LabelledBinaryTree
2958
sage: t1 = LBT([[LBT([], label=2), None], None], label=4); t1
2959
4[None[2[., .], .], .]
2960
sage: LBT([[],[[], None]], label = 3) # indirect doctest
2961
3[None[., .], None[None[., .], .]]
2962
"""
2963
if not self:
2964
if self._label is not None:
2965
return repr(self._label)
2966
else:
2967
return "."
2968
else:
2969
return "%s%s"%(self._label, self[:])
2970
2971
def binary_search_insert(self, letter):
2972
"""
2973
Return the result of inserting a letter ``letter`` into the
2974
right strict binary search tree ``self``.
2975
2976
INPUT:
2977
2978
- ``letter`` -- any object comparable with the labels of ``self``
2979
2980
OUTPUT:
2981
2982
The right strict binary search tree ``self`` with ``letter``
2983
inserted into it according to the binary search insertion
2984
algorithm.
2985
2986
.. NOTE:: ``self`` is supposed to be a binary search tree.
2987
This is not being checked!
2988
2989
A right strict binary search tree is defined to be a labelled
2990
binary tree such that for each node `n` with label `x`,
2991
every descendant of the left child of `n` has a label `\leq x`,
2992
and every descendant of the right child of `n` has a label
2993
`> x`. (Here, only nodes count as descendants, and every node
2994
counts as its own descendant too.) Leaves are assumed to have
2995
no labels.
2996
2997
Given a right strict binary search tree `t` and a letter `i`,
2998
the result of inserting `i` into `t` (denoted `Ins(i, t)` in
2999
the following) is defined recursively as follows:
3000
3001
- If `t` is empty, then `Ins(i, t)` is the tree with one node
3002
only, and this node is labelled with `i`.
3003
3004
- Otherwise, let `j` be the label of the root of `t`. If
3005
`i > j`, then `Ins(i, t)` is obtained by replacing the
3006
right child of `t` by `Ins(i, r)` in `t`, where `r` denotes
3007
the right child of `t`. If `i \leq j`, then `Ins(i, t)` is
3008
obtained by replacing the left child of `t` by `Ins(i, l)`
3009
in `t`, where `l` denotes the left child of `t`.
3010
3011
See, for example, [HNT05]_ for properties of this algorithm.
3012
3013
.. WARNING::
3014
3015
If `t` is nonempty, then inserting `i` into `t` does not
3016
change the root label of `t`. Hence, as opposed to
3017
algorithms like Robinson-Schensted-Knuth, binary
3018
search tree insertion involves no bumping.
3019
3020
EXAMPLES:
3021
3022
The example from Fig. 2 of [HNT05]_::
3023
3024
sage: LBT = LabelledBinaryTree
3025
sage: x = LBT(None)
3026
sage: x
3027
.
3028
sage: x = x.binary_search_insert("b"); x
3029
b[., .]
3030
sage: x = x.binary_search_insert("d"); x
3031
b[., d[., .]]
3032
sage: x = x.binary_search_insert("e"); x
3033
b[., d[., e[., .]]]
3034
sage: x = x.binary_search_insert("a"); x
3035
b[a[., .], d[., e[., .]]]
3036
sage: x = x.binary_search_insert("b"); x
3037
b[a[., b[., .]], d[., e[., .]]]
3038
sage: x = x.binary_search_insert("d"); x
3039
b[a[., b[., .]], d[d[., .], e[., .]]]
3040
sage: x = x.binary_search_insert("a"); x
3041
b[a[a[., .], b[., .]], d[d[., .], e[., .]]]
3042
sage: x = x.binary_search_insert("c"); x
3043
b[a[a[., .], b[., .]], d[d[c[., .], .], e[., .]]]
3044
3045
Other examples::
3046
3047
sage: LBT = LabelledBinaryTree
3048
sage: LBT(None).binary_search_insert(3)
3049
3[., .]
3050
sage: LBT([], label = 1).binary_search_insert(3)
3051
1[., 3[., .]]
3052
sage: LBT([], label = 3).binary_search_insert(1)
3053
3[1[., .], .]
3054
sage: res = LBT(None)
3055
sage: for i in [3,1,5,2,4,6]:
3056
....: res = res.binary_search_insert(i)
3057
sage: res
3058
3[1[., 2[., .]], 5[4[., .], 6[., .]]]
3059
"""
3060
LT = self.parent()._element_constructor_
3061
if not self:
3062
return LT([], label = letter)
3063
else:
3064
if letter <= self.label():
3065
fils = self[0].binary_search_insert(letter)
3066
return LT([fils, self[1]], label=self.label())
3067
else:
3068
fils = self[1].binary_search_insert(letter)
3069
return LT([self[0], fils], label=self.label())
3070
3071
def semistandard_insert(self, letter):
3072
"""
3073
Return the result of inserting a letter ``letter`` into the
3074
semistandard tree ``self`` using the bumping algorithm.
3075
3076
INPUT:
3077
3078
- ``letter`` -- any object comparable with the labels of ``self``
3079
3080
OUTPUT:
3081
3082
The semistandard tree ``self`` with ``letter`` inserted into it
3083
according to the bumping algorithm.
3084
3085
.. NOTE:: ``self`` is supposed to be a semistandard tree.
3086
This is not being checked!
3087
3088
A semistandard tree is defined to be a labelled binary tree
3089
such that for each node `n` with label `x`, every descendant of
3090
the left child of `n` has a label `> x`, and every descendant
3091
of the right child of `n` has a label `\geq x`. (Here, only
3092
nodes count as descendants, and every node counts as its own
3093
descendant too.) Leaves are assumed to have no labels.
3094
3095
Given a semistandard tree `t` and a letter `i`, the result of
3096
inserting `i` into `t` (denoted `Ins(i, t)` in the following)
3097
is defined recursively as follows:
3098
3099
- If `t` is empty, then `Ins(i, t)` is the tree with one node
3100
only, and this node is labelled with `i`.
3101
3102
- Otherwise, let `j` be the label of the root of `t`. If
3103
`i \geq j`, then `Ins(i, t)` is obtained by replacing the
3104
right child of `t` by `Ins(i, r)` in `t`, where `r` denotes
3105
the right child of `t`. If `i < j`, then `Ins(i, t)` is
3106
obtained by replacing the label at the root of `t` by `i`,
3107
and replacing the left child of `t` by `Ins(j, l)`
3108
in `t`, where `l` denotes the left child of `t`.
3109
3110
This algorithm is similar to the Robinson-Schensted-Knuth
3111
insertion algorithm for semistandard Young tableaux.
3112
3113
AUTHORS:
3114
3115
- Darij Grinberg (10 Nov 2013).
3116
3117
EXAMPLES::
3118
3119
sage: LBT = LabelledBinaryTree
3120
sage: x = LBT(None)
3121
sage: x
3122
.
3123
sage: x = x.semistandard_insert("b"); x
3124
b[., .]
3125
sage: x = x.semistandard_insert("d"); x
3126
b[., d[., .]]
3127
sage: x = x.semistandard_insert("e"); x
3128
b[., d[., e[., .]]]
3129
sage: x = x.semistandard_insert("a"); x
3130
a[b[., .], d[., e[., .]]]
3131
sage: x = x.semistandard_insert("b"); x
3132
a[b[., .], b[d[., .], e[., .]]]
3133
sage: x = x.semistandard_insert("d"); x
3134
a[b[., .], b[d[., .], d[e[., .], .]]]
3135
sage: x = x.semistandard_insert("a"); x
3136
a[b[., .], a[b[d[., .], .], d[e[., .], .]]]
3137
sage: x = x.semistandard_insert("c"); x
3138
a[b[., .], a[b[d[., .], .], c[d[e[., .], .], .]]]
3139
3140
Other examples::
3141
3142
sage: LBT = LabelledBinaryTree
3143
sage: LBT(None).semistandard_insert(3)
3144
3[., .]
3145
sage: LBT([], label = 1).semistandard_insert(3)
3146
1[., 3[., .]]
3147
sage: LBT([], label = 3).semistandard_insert(1)
3148
1[3[., .], .]
3149
sage: res = LBT(None)
3150
sage: for i in [3,1,5,2,4,6]:
3151
....: res = res.semistandard_insert(i)
3152
sage: res
3153
1[3[., .], 2[5[., .], 4[., 6[., .]]]]
3154
"""
3155
LT = self.parent()._element_constructor_
3156
if not self:
3157
return LT([], label = letter)
3158
else:
3159
root_label = self.label()
3160
if letter < root_label:
3161
fils = self[0].semistandard_insert(root_label)
3162
return LT([fils, self[1]], label=letter)
3163
else:
3164
fils = self[1].semistandard_insert(letter)
3165
return LT([self[0], fils], label=root_label)
3166
3167
def right_rotate(self):
3168
r"""
3169
Return the result of right rotation applied to the labelled
3170
binary tree ``self``.
3171
3172
Right rotation on labelled binary trees is defined as
3173
follows: Let `T` be a labelled binary tree such that the
3174
left child of the root of `T` is a node. Let
3175
`C` be the right child of the root of `T`, and let `A`
3176
and `B` be the left and right children of the left child
3177
of the root of `T`. (Keep in mind that nodes of trees are
3178
identified with the subtrees consisting of their
3179
descendants.) Furthermore, let `y` be the label at the
3180
root of `T`, and `x` be the label at the left child of the
3181
root of `T`.
3182
Then, the right rotation of `T` is the labelled binary
3183
tree in which the root is labelled `x`, the left child of
3184
the root is `A`, whereas the right child of the root is a
3185
node labelled `y` whose left and right children are `B`
3186
and `C`. In pictures::
3187
3188
| y x |
3189
| / \ / \ |
3190
| x C -right-rotate-> A y |
3191
| / \ / \ |
3192
| A B B C |
3193
3194
Right rotation is the inverse operation to left rotation
3195
(:meth:`left_rotate`).
3196
3197
TESTS::
3198
3199
sage: LB = LabelledBinaryTree
3200
sage: b = LB([LB([LB([],"A"), LB([],"B")],"x"),LB([],"C")], "y"); b
3201
y[x[A[., .], B[., .]], C[., .]]
3202
sage: b.right_rotate()
3203
x[A[., .], y[B[., .], C[., .]]]
3204
"""
3205
B = self.parent()._element_constructor_
3206
s0 = self[0]
3207
return B([s0[0], B([s0[1], self[1]], self.label())], s0.label())
3208
3209
def left_rotate(self):
3210
r"""
3211
Return the result of left rotation applied to the labelled
3212
binary tree ``self``.
3213
3214
Left rotation on labelled binary trees is defined as
3215
follows: Let `T` be a labelled binary tree such that the
3216
right child of the root of `T` is a node. Let
3217
`A` be the left child of the root of `T`, and let `B`
3218
and `C` be the left and right children of the right child
3219
of the root of `T`. (Keep in mind that nodes of trees are
3220
identified with the subtrees consisting of their
3221
descendants.) Furthermore, let `x` be the label at the
3222
root of `T`, and `y` be the label at the right child of the
3223
root of `T`.
3224
Then, the left rotation of `T` is the labelled binary tree
3225
in which the root is labelled `y`, the right child of the
3226
root is `C`, whereas the left child of the root is a node
3227
labelled `x` whose left and right children are `A` and `B`.
3228
In pictures::
3229
3230
| y x |
3231
| / \ / \ |
3232
| x C <-left-rotate- A y |
3233
| / \ / \ |
3234
| A B B C |
3235
3236
Left rotation is the inverse operation to right rotation
3237
(:meth:`right_rotate`).
3238
3239
TESTS::
3240
3241
sage: LB = LabelledBinaryTree
3242
sage: b = LB([LB([LB([],"A"), LB([],"B")],"x"),LB([],"C")], "y"); b
3243
y[x[A[., .], B[., .]], C[., .]]
3244
sage: b == b.right_rotate().left_rotate()
3245
True
3246
"""
3247
B = self.parent()._element_constructor_
3248
s1 = self[1]
3249
return B([B([self[0], s1[0]], self.label()), s1[1]], s1.label())
3250
3251
def heap_insert(self, l):
3252
r"""
3253
Return the result of inserting a letter ``l`` into the binary
3254
heap (tree) ``self``.
3255
3256
A binary heap is a labelled complete binary tree such that for
3257
each node, the label at the node is greater or equal to the
3258
label of each of its child nodes. (More precisely, this is
3259
called a max-heap.)
3260
3261
For example::
3262
3263
| _7_ |
3264
| / \ |
3265
| 5 6 |
3266
| / \ |
3267
| 3 4 |
3268
3269
is a binary heap.
3270
3271
See :wikipedia:`Binary_heap#Insert` for a description of how to
3272
insert a letter into a binary heap. The result is another binary
3273
heap.
3274
3275
INPUT:
3276
3277
- ``letter`` -- any object comparable with the labels of ``self``
3278
3279
.. NOTE::
3280
3281
``self`` is assumed to be a binary heap (tree). No check is
3282
performed.
3283
3284
TESTS::
3285
3286
sage: h = LabelledBinaryTree(None)
3287
sage: h = h.heap_insert(3); ascii_art([h])
3288
[ 3 ]
3289
sage: h = h.heap_insert(4); ascii_art([h])
3290
[ 4 ]
3291
[ / ]
3292
[ 3 ]
3293
sage: h = h.heap_insert(6); ascii_art([h])
3294
[ 6 ]
3295
[ / \ ]
3296
[ 3 4 ]
3297
sage: h = h.heap_insert(2); ascii_art([h])
3298
[ 6 ]
3299
[ / \ ]
3300
[ 3 4 ]
3301
[ / ]
3302
[ 2 ]
3303
sage: ascii_art([h.heap_insert(5)])
3304
[ _6_ ]
3305
[ / \ ]
3306
[ 5 4 ]
3307
[ / \ ]
3308
[ 2 3 ]
3309
"""
3310
B = self.parent()._element_constructor_
3311
if self.is_empty():
3312
return B([], l)
3313
3314
if self.label() < l:
3315
label_root = l
3316
label_insert = self.label()
3317
else:
3318
label_root = self.label()
3319
label_insert = l
3320
L, R = self
3321
dL = L.depth()
3322
dR = R.depth()
3323
# if depth of L is greater than the depth of R
3324
if dL > dR:
3325
# if L is perfect we insert in R
3326
if L.is_perfect():
3327
return B([L, R.heap_insert(label_insert)], label_root)
3328
# we insert in L
3329
return B([L.heap_insert(label_insert), R], label_root)
3330
# else ==> dL == dR
3331
# if R is perfect we have to insert on the leftmost leaf
3332
if R.is_perfect():
3333
# ## TODO:: can be optimized...
3334
return B([L.heap_insert(label_insert), R], label_root)
3335
# else we insert on the right
3336
return B([L, R.heap_insert(label_insert)], label_root)
3337
3338
_UnLabelled = BinaryTree
3339
3340
3341
class LabelledBinaryTrees(LabelledOrderedTrees):
3342
"""
3343
This is a parent stub to serve as a factory class for trees with various
3344
labels constraints.
3345
"""
3346
def _repr_(self):
3347
"""
3348
TESTS::
3349
3350
sage: LabelledBinaryTrees() # indirect doctest
3351
Labelled binary trees
3352
"""
3353
return "Labelled binary trees"
3354
3355
def _an_element_(self):
3356
"""
3357
Return a labelled binary tree.
3358
3359
EXAMPLE::
3360
3361
sage: LabelledBinaryTrees().an_element() # indirect doctest
3362
toto[42[3[., .], 3[., .]], 5[None[., .], None[., .]]]
3363
"""
3364
LT = self._element_constructor_
3365
t = LT([], label = 3)
3366
t1 = LT([t,t], label = 42)
3367
t2 = LT([[], []], label = 5)
3368
return LT([t1,t2], label = "toto")
3369
3370
def unlabelled_trees(self):
3371
"""
3372
Return the set of unlabelled trees associated to ``self``.
3373
3374
EXAMPLES::
3375
3376
sage: LabelledBinaryTrees().unlabelled_trees()
3377
Binary trees
3378
3379
This is used to compute the shape::
3380
3381
sage: t = LabelledBinaryTrees().an_element().shape(); t
3382
[[[., .], [., .]], [[., .], [., .]]]
3383
sage: t.parent()
3384
Binary trees
3385
3386
TESTS::
3387
3388
sage: t = LabelledBinaryTrees().an_element()
3389
sage: t.canonical_labelling()
3390
4[2[1[., .], 3[., .]], 6[5[., .], 7[., .]]]
3391
"""
3392
return BinaryTrees_all()
3393
3394
def labelled_trees(self):
3395
"""
3396
Return the set of labelled trees associated to ``self``.
3397
3398
EXAMPLES::
3399
3400
sage: LabelledBinaryTrees().labelled_trees()
3401
Labelled binary trees
3402
"""
3403
return self
3404
3405
Element = LabelledBinaryTree
3406
3407
3408
3409
################################################################
3410
# Interface attempt with species...
3411
#
3412
# Kept here for further reference when species will be improved
3413
################################################################
3414
# from sage.combinat.species.library import (
3415
# CombinatorialSpecies, EmptySetSpecies, SingletonSpecies)
3416
3417
# BT = CombinatorialSpecies()
3418
# F = EmptySetSpecies()
3419
# N = SingletonSpecies()
3420
# BT.define(F+N*(BT*BT))
3421
# # b3 = BT.isotypes(range(3))
3422
# # tr = b3.list()[1]
3423
3424
# def BTsp_to_bintrees(bt):
3425
# """
3426
# sage: from sage.combinat.binary_tree import BT, BTsp_to_bintrees
3427
# sage: BTsp_to_bintrees(BT.isotypes(range(5))[0])
3428
# [., [., [., [., [., .]]]]]
3429
# sage: def spls(size):
3430
# ....: return map(BTsp_to_bintrees, BT.isotypes(range(size)).list())
3431
# sage: spls(3)
3432
# [[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]]
3433
# sage: all(spls(i) == BinaryTrees(i).list() for i in range(5))
3434
# True
3435
# """
3436
# if len(bt) == 0:
3437
# return BinaryTree()
3438
# elif len(bt) == 2 and len(bt[1]) == 2:
3439
# return BinaryTree(map(BTsp_to_bintrees, list(bt[1])))
3440
# else:
3441
# raise ValueError
3442
3443