Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/dev/test/data/trac_8703-trees-fh.patch
8817 views
1
#8703: Enumerated sets and data structure for ordered and binary trees
2
- The Class Abstract[Labelled]Tree allows for inheritance from different
3
Cython classes.
4
- Added shape on labelled trees.
5
- Add a new function as_digraph() that maps a tree to the associated directed
6
graph, with edges oriented away from from the root
7
- Added canopee to binary trees.
8
- Decreasing and increasing Binary tree of a permutations.
9
- Added Binary tree insertion.
10
- Added Binary search tree of a permutation
11
- removed sage.misc.sagex_ds.BinaryTree from the interface.
12
13
diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
14
--- a/doc/en/reference/combinat/index.rst
15
+++ b/doc/en/reference/combinat/index.rst
16
@@ -45,6 +45,9 @@ Combinatorics
17
sage/combinat/sidon_sets
18
sage/combinat/set_partition_ordered
19
sage/combinat/set_partition
20
+ sage/combinat/abstract_tree
21
+ sage/combinat/ordered_tree
22
+ sage/combinat/binary_tree
23
sage/combinat/skew_partition
24
sage/combinat/subset
25
sage/combinat/subsets_pairwise
26
diff --git a/sage/combinat/abstract_tree.py b/sage/combinat/abstract_tree.py
27
new file mode 100644
28
--- /dev/null
29
+++ b/sage/combinat/abstract_tree.py
30
@@ -0,0 +1,979 @@
31
+"""
32
+Abstract Recursive Trees
33
+
34
+The purpose of this class is to help implement trees with a specific structure
35
+on the children of each node. For instance, one could want to define a tree in
36
+which each node sees its children as linearly (see the :mod:`Ordered Trees
37
+<sage.combinat.ordered_tree>` module) or cyclically ordered.
38
+
39
+**Tree structures**
40
+
41
+Conceptually, one can define a tree structure from any object that can contain
42
+others. Indeed, a list can contain lists which contain lists which contain
43
+lists, and thus define a tree ... The same can be done with sets, or any kind
44
+of iterable objects.
45
+
46
+While any iterable is sufficient to encode trees, it can prove useful to have
47
+other methods available like isomorphism tests (see next section), conversions
48
+to DiGraphs objects (see :meth:`~.AbstractLabelledTree.as_digraph`) or
49
+computation of the number of automorphisms constrained by the structure on
50
+children. Providing such methods is the whole purpose of the
51
+:class:`AbstractTree` class.
52
+
53
+As a result, the :class:`AbstractTree` class is not meant to be
54
+instantiated, but extended. It is expected that classes extending this one may
55
+also inherit from classes representing iterables, for instance
56
+:class:`ClonableArray` or :class:`~sage.structure.list_clone.ClonableList`
57
+
58
+**Constrained Trees**
59
+
60
+The tree built from a specific container will reflect the properties of the
61
+container. Indeed, if ``A`` is an iterable class whose elements are linearly
62
+ordered, a class ``B`` extending both of :class:`AbstractTree` and ``A`` will
63
+be such that the children of a node will be linearly ordered. If ``A`` behaves
64
+like a set (i.e. if there is no order on the elements it contains), then two
65
+trees will be considered as equal if one can be obtained from the other
66
+through permutations between the children of a same node (see next section).
67
+
68
+**Paths and ID**
69
+
70
+It is expected that each element of a set of children should be identified by
71
+its index in the container. This way, any node of the tree can be identified
72
+by a word describing a path from the root node.
73
+
74
+**Canonical labellings**
75
+
76
+Equality between instances of classes extending both of :class:`AbstractTree`
77
+and ``A`` is entirely defined by the equality defined on the elements of
78
+``A``. A canonical labelling of such a tree however, should be such that two
79
+trees ``a`` and ``b`` satisfying ``a == b`` should have the same canonical
80
+labellings. On the other hand, the canonical labellings of trees ``a`` and
81
+``b`` satisfying ``a != b`` are expected to be different.
82
+
83
+For this reason, the values returned by the :meth:`canonical_labelling
84
+<AbstractTree.canonical_labelling>` method heavily
85
+depend on the data structure used for a node's children and **should be**
86
+**overridden** by most of the classes extending :class:`AbstractTree` if it is
87
+incoherent with the data structure.
88
+
89
+**Authors**
90
+
91
+- Florent Hivert (2010-2011): initial revision
92
+- Frederic Chapoton (2011): contributed some methods
93
+"""
94
+
95
+from sage.structure.list_clone import ClonableArray
96
+from sage.rings.integer import Integer
97
+from sage.misc.misc_c import prod
98
+
99
+# Unfortunately Cython forbids multiple inheritance. Therefore, we do not
100
+# inherits from SageObject to be able to inherits from Element or a subclass
101
+# of it later.
102
+class AbstractTree(object):
103
+ """
104
+ Abstract Tree
105
+
106
+ There is no data structure defined here, as this class is meant to be
107
+ extended, not instantiated.
108
+
109
+ .. rubric:: How should this class be extended ?
110
+
111
+ A class extending :class:`AbstractTree
112
+ <sage.combinat.abstract_tree.AbstractTree>` should respect several
113
+ assumptions:
114
+
115
+ * For a tree ``T``, the call ``iter(T)`` should return an iterator on the
116
+ children of the root ``T``.
117
+
118
+ * The :meth:`canonical_labelling
119
+ <AbstractTree.canonical_labelling>` method
120
+ should return the same value for trees that are considered equal (see the
121
+ "canonical labellings" section in the documentation of the
122
+ :class:`AbstractTree <sage.combinat.abstract_tree.AbstractTree>` module).
123
+
124
+ * For a tree ``T`` the call ``T.parent().labelled_trees()`` should return
125
+ a parent for labelled trees of the same kind: for example,
126
+
127
+ - if ``T`` is a binary tree, ``T.parent()`` is ``BinaryTrees()`` and
128
+ ``T.parent().labelled_trees()`` is ``LabelledBinaryTrees()``
129
+
130
+ - if ``T`` is an ordered tree, ``T.parent()`` is ``OrderedTrees()`` and
131
+ ``T.parent().labelled_trees()`` is ``LabelledOrderedTrees()``
132
+
133
+ TESTS::
134
+
135
+ sage: TestSuite(OrderedTree()).run()
136
+ sage: TestSuite(BinaryTree()).run()
137
+ """
138
+
139
+ def subtrees(self):
140
+ """
141
+ Returns a generator for all subtrees of ``self``
142
+
143
+ The number of subtrees of a tree is its number of elements.
144
+
145
+ EXAMPLES::
146
+
147
+ sage: list(OrderedTree([]).subtrees())
148
+ [[]]
149
+ sage: list(OrderedTree([[],[[]]]).subtrees())
150
+ [[[], [[]]], [], [[]], []]
151
+
152
+ sage: list(BinaryTree([[],[[],[]]]).subtrees())
153
+ [[[., .], [[., .], [., .]]], [., .], [[., .], [., .]], [., .], [., .]]
154
+
155
+ TESTS::
156
+
157
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
158
+ sage: t.node_number() == len(list(t.subtrees()))
159
+ True
160
+ sage: list(BinaryTree().subtrees())
161
+ []
162
+ sage: bt = BinaryTree([[],[[],[]]])
163
+ sage: bt.node_number() == len(list(bt.subtrees()))
164
+ True
165
+ """
166
+ if not self.is_empty():
167
+ yield self
168
+ for i in self:
169
+ for t in i.subtrees():
170
+ yield t
171
+
172
+ def paths(self):
173
+ """
174
+ Returns a generator for all paths to nodes of ``self``
175
+
176
+ OUTPUT:
177
+
178
+ This method returns a list of sequences of integers. Each of these
179
+ sequences represents a path from the root node to another one : `(1, 3,
180
+ 2, 5, 3)` represents the node obtained by chosing the 1st children of
181
+ the root node (in the ordering returned by ``iter``), then the 3rd of
182
+ its children, then the 2nd of this element, etc.
183
+
184
+ The root element is represented by the empty tuple ``()``.
185
+
186
+ EXAMPLES::
187
+
188
+ sage: list(OrderedTree([]).paths())
189
+ [()]
190
+ sage: list(OrderedTree([[],[[]]]).paths())
191
+ [(), (0,), (1,), (1, 0)]
192
+
193
+ sage: list(BinaryTree([[],[[],[]]]).paths())
194
+ [(), (0,), (1,), (1, 0), (1, 1)]
195
+
196
+ TESTS::
197
+
198
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
199
+ sage: t.node_number() == len(list(t.paths()))
200
+ True
201
+ sage: list(BinaryTree().paths())
202
+ []
203
+ sage: bt = BinaryTree([[],[[],[]]])
204
+ sage: bt.node_number() == len(list(bt.paths()))
205
+ True
206
+ """
207
+ if not self.is_empty():
208
+ yield ()
209
+ for i, t in enumerate(self):
210
+ for p in t.paths():
211
+ yield (i,)+p
212
+
213
+ def node_number(self):
214
+ """
215
+ The number of nodes of ``self``
216
+
217
+ EXAMPLES::
218
+
219
+ sage: OrderedTree().node_number()
220
+ 1
221
+ sage: OrderedTree([]).node_number()
222
+ 1
223
+ sage: OrderedTree([[],[]]).node_number()
224
+ 3
225
+ sage: OrderedTree([[],[[]]]).node_number()
226
+ 4
227
+ sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number()
228
+ 13
229
+
230
+ EXAMPLE::
231
+
232
+ sage: BinaryTree(None).node_number()
233
+ 0
234
+ sage: BinaryTree([]).node_number()
235
+ 1
236
+ sage: BinaryTree([[], None]).node_number()
237
+ 2
238
+ sage: BinaryTree([[None, [[], []]], None]).node_number()
239
+ 5
240
+ """
241
+ if self.is_empty():
242
+ return 0
243
+ else:
244
+ return sum((i.node_number() for i in self), Integer(1))
245
+
246
+ def depth(self):
247
+ """
248
+ The depth of ``self``
249
+
250
+ EXAMPLES::
251
+
252
+ sage: OrderedTree().depth()
253
+ 1
254
+ sage: OrderedTree([]).depth()
255
+ 1
256
+ sage: OrderedTree([[],[]]).depth()
257
+ 2
258
+ sage: OrderedTree([[],[[]]]).depth()
259
+ 3
260
+ sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).depth()
261
+ 4
262
+
263
+ sage: BinaryTree().depth()
264
+ 0
265
+ sage: BinaryTree([[],[[],[]]]).depth()
266
+ 3
267
+ """
268
+ if self:
269
+ return Integer(1 + max(i.depth() for i in self))
270
+ else:
271
+ return Integer(0 if self.is_empty() else 1)
272
+
273
+ def canonical_labelling(self,shift=1):
274
+ """
275
+ Returns a labelled version of ``self``
276
+
277
+ The actual canonical labelling is currently unspecified. However, it
278
+ is guaranteed to have labels in `1...n` where `n` is the number of
279
+ nodes of the tree. Moreover, two (unlabelled) trees compare as equal if
280
+ and only if they canonical labelled trees compare as equal.
281
+
282
+ EXAMPLES::
283
+
284
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
285
+ sage: t.canonical_labelling()
286
+ 1[2[], 3[4[], 5[6[], 7[]], 8[9[], 10[]]], 11[12[], 13[]]]
287
+
288
+ sage: BinaryTree([]).canonical_labelling()
289
+ 1[., .]
290
+ sage: BinaryTree([[],[[],[]]]).canonical_labelling()
291
+ 2[1[., .], 4[3[., .], 5[., .]]]
292
+
293
+ TESTS::
294
+
295
+ sage: BinaryTree().canonical_labelling()
296
+ .
297
+ """
298
+ LTR = self.parent().labelled_trees()
299
+ liste=[]
300
+ deca=1
301
+ for subtree in self:
302
+ liste=liste+[subtree.canonical_labelling(shift+deca)]
303
+ deca=deca+subtree.node_number()
304
+ return LTR._element_constructor_(liste,label=shift)
305
+
306
+ def tree_factorial(self):
307
+ """
308
+ Returns the tree-factorial of ``self``
309
+
310
+ Definition:
311
+
312
+ The tree-factorial `T!` of a tree `T` is the product `\prod_{v\in
313
+ T}\#\mbox{children}(v)`.
314
+
315
+ EXAMPLES::
316
+
317
+ sage: LT=LabelledOrderedTrees()
318
+ sage: t=LT([LT([],label=6),LT([],label=1)],label=9)
319
+ sage: t.tree_factorial()
320
+ 3
321
+
322
+ sage: BinaryTree([[],[[],[]]]).tree_factorial()
323
+ 15
324
+
325
+ TESTS::
326
+
327
+ sage: BinaryTree().tree_factorial()
328
+ 1
329
+ """
330
+ nb = self.node_number()
331
+ if nb <= 1:
332
+ return 1
333
+ else:
334
+ return nb*prod(s.tree_factorial() for s in self)
335
+
336
+ latex_unit_length = "4mm"
337
+ latex_node_diameter = "0.5"
338
+ latex_root_diameter = "0.7"
339
+
340
+ def _latex_(self):
341
+ """
342
+ Returns a LaTeX version of ``self``
343
+
344
+ EXAMPLES::
345
+
346
+ sage: print(OrderedTree([[],[]])._latex_())
347
+ \vcenter{\hbox{{\setlength\unitlength{4mm}
348
+ \begin{picture}(4,3)
349
+ \put(1,1){\circle*{0.5}}
350
+ \put(2,2){\circle*{0.5}}
351
+ \put(3,1){\circle*{0.5}}
352
+ \put(2,2){\line(-1,-1){1}}
353
+ \put(2,2){\line(1,-1){1}}
354
+ \put(2,2){\circle*{0.7}}
355
+ \end{picture}}}}
356
+
357
+ TESTS::
358
+
359
+ sage: OrderedTree([])._latex_()
360
+ '\\vcenter{\\hbox{{\\setlength\\unitlength{4mm}\n\\begin{picture}(2,2)\n\\put(1,1){\\circle*{0.5}}\n\\put(1,1){\\circle*{0.7}}\n\\end{picture}}}}'
361
+ sage: OrderedTree([[]])._latex_()
362
+ '\\vcenter{\\hbox{{\\setlength\\unitlength{4mm}\n\\begin{picture}(2,3)\n\\put(1,1){\\circle*{0.5}}\n\\put(1,2){\\circle*{0.5}}\n\\put(1,2){\\line(0,-1){1}}\n\\put(1,2){\\circle*{0.7}}\n\\end{picture}}}}'
363
+ sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]])._latex_()
364
+ '\\vcenter{\\hbox{{\\setlength\\unitlength{4mm}\n\\begin{picture}(12,5)\n\\put(1,3){\\circle*{0.5}}\n\\put(2,2){\\circle*{0.5}}\n\\put(3,1){\\circle*{0.5}}\n\\put(4,2){\\circle*{0.5}}\n\\put(5,1){\\circle*{0.5}}\n\\put(4,2){\\line(-1,-1){1}}\n\\put(4,2){\\line(1,-1){1}}\n\\put(4,3){\\circle*{0.5}}\n\\put(6,1){\\circle*{0.5}}\n\\put(7,2){\\circle*{0.5}}\n\\put(8,1){\\circle*{0.5}}\n\\put(7,2){\\line(-1,-1){1}}\n\\put(7,2){\\line(1,-1){1}}\n\\put(4,3){\\line(-2,-1){2}}\n\\put(4,3){\\line(0,-1){1}}\n\\put(4,3){\\line(3,-1){3}}\n\\put(4,4){\\circle*{0.5}}\n\\put(9,2){\\circle*{0.5}}\n\\put(10,3){\\circle*{0.5}}\n\\put(11,2){\\circle*{0.5}}\n\\put(10,3){\\line(-1,-1){1}}\n\\put(10,3){\\line(1,-1){1}}\n\\put(4,4){\\line(-3,-1){3}}\n\\put(4,4){\\line(0,-1){1}}\n\\put(4,4){\\line(6,-1){6}}\n\\put(4,4){\\circle*{0.7}}\n\\end{picture}}}}'
365
+ """
366
+ from sage.misc.latex import latex
367
+ drawing = [""] # allows modification of in rec...
368
+ x = [1] # allows modification of x[0] in rec...
369
+ max_label_width = [0] # allows modification of x[0] in rec...
370
+ maxy = self.depth()
371
+
372
+ def rec(t, y):
373
+ """
374
+ Draw the subtree t on the drawing, below y (included) and to
375
+ the right of x[0] (included). Update x[0]. Returns the horizontal
376
+ position of the root
377
+ """
378
+ if t.node_number() == 0 : return -1
379
+ n = len(t)
380
+ posChild = [rec(t[i], y+1) for i in range(n // 2)]
381
+ i = n // 2
382
+ if n % 2 == 1:
383
+ xc = rec(t[i], y+1)
384
+ posChild.append(xc)
385
+ i += 1
386
+ else:
387
+ xc = x[0]
388
+ x[0] +=1
389
+ drawing[0] = drawing[0] + "\\put(%s,%s){\\circle*{%s}}\n"%(
390
+ xc, maxy-y, self.latex_node_diameter)
391
+ try:
392
+ lbl = t.label()
393
+ except AttributeError:
394
+ pass
395
+ else:
396
+ max_label_width[0] = 1 # TODO find a better heuristic
397
+ drawing[0] = drawing[0] + "\\put(%s,%s){$\scriptstyle %s$}"%(
398
+ xc+0.3, maxy-y-0.3, latex(lbl))
399
+ posChild += [rec(t[j], y+1) for j in range(i, n)]
400
+ for i in range(n):
401
+ if posChild[i] != -1:
402
+ drawing[0] = (drawing[0] +
403
+ "\\put(%s,%s){\\line(%s,-1){%s}}\n"%(
404
+ xc, maxy-y, posChild[i]-xc,
405
+ max(abs(posChild[i]-xc), 1)))
406
+ return xc
407
+
408
+ res = rec(self, 0)
409
+ drawing[0] = drawing[0] + "\\put(%s,%s){\\circle*{%s}}\n"%(
410
+ res, maxy, self.latex_root_diameter)
411
+ return "\\vcenter{\hbox{{\setlength\unitlength{%s}\n\\begin{picture}(%s,%s)\n%s\\end{picture}}}}"%(
412
+ self.latex_unit_length,
413
+ x[0] + max_label_width[0],
414
+ maxy + 1,
415
+ drawing[0])
416
+
417
+class AbstractClonableTree(AbstractTree):
418
+ """
419
+ Abstract Clonable Tree
420
+
421
+ An abstract class for trees with clone protocol (see
422
+ :mod:`~sage.structure.list_clone`). It is expected that classes extending
423
+ this one may also inherit from classes like :class:`ClonableArray` or
424
+ :class:`~sage.structure.list_clone.ClonableList` depending wether one
425
+ wants to build trees where adding a child is allowed.
426
+
427
+ .. note:: Due to the limitation of Cython inheritance, one cannot inherit
428
+ here from :class:`~sage.structure.list_clone.ClonableElement`, because
429
+ it would prevent us to inherit later from
430
+ :class:`~sage.structure.list_clone.ClonableArray` or
431
+ :class:`~sage.structure.list_clone.ClonableList`.
432
+
433
+ .. rubric:: How should this class be extended ?
434
+
435
+ A class extending :class:`AbstractTree
436
+ <sage.combinat.abstract_tree.AbstractTree>` should the following
437
+ assumptions:
438
+
439
+ * An instantiable class extending :class:`AbstractTree
440
+ <sage.combinat.abstract_tree.AbstractTree>` should also extend the
441
+ :class:`ClonableElement <sage.structure.list_clone.ClonableElement>`
442
+ class or one of its subclass generally at least :class:`ClonableArray
443
+ <sage.structure.list_clone.ClonableArray>`.
444
+
445
+
446
+ * To respect the Clone protocol, the :meth:`AbstractClonableTree.check`
447
+ method should be overridden by the new class.
448
+ """
449
+ def check(self):
450
+ """
451
+ Check that ``self`` is a correct tree
452
+
453
+ This method does nothing. It is implemented here because many
454
+ extensions of :class:`AbstractTree
455
+ <sage.combinat.abstract_tree.AbstractTree>` also extend
456
+ :class:`sage.structure.list_clone.ClonableElement`, which requires it.
457
+
458
+ It should be overriden in subclass is order to chech that the
459
+ invariant of the kind of tree holds (eg: two children for binary
460
+ trees).
461
+
462
+ EXAMPLES::
463
+
464
+ sage: OrderedTree([[],[[]]]).check()
465
+ sage: BinaryTree([[],[[],[]]]).check()
466
+ """
467
+ pass
468
+
469
+ def __setitem__(self, idx, value):
470
+ """
471
+ Substitute a subtree
472
+
473
+ .. NOTE::
474
+
475
+ The tree ``self`` must be in a mutable state. See
476
+ :mod:`sage.structure.list_clone` for more details about
477
+ mutability. The default implementation here assume that the
478
+ container of the node implement a method `_setitem` with signature
479
+ `self._setitem(idx, value)`. It is usually provided by inheriting
480
+ from :class:`~sage.structure.list_clone.ClonableArray`.
481
+
482
+ INPUT:
483
+
484
+ - ``idx`` -- a valid path in ``self`` identifying a node
485
+
486
+ - ``value`` -- the tree to be substituted
487
+
488
+ EXAMPLES:
489
+
490
+ Trying to modify a non mutable tree raise an error::
491
+
492
+ sage: x = OrderedTree([])
493
+ sage: x[0] = OrderedTree([[]])
494
+ Traceback (most recent call last):
495
+ ...
496
+ ValueError: object is immutable; please change a copy instead.
497
+
498
+ Here is the correct way to do it::
499
+
500
+ sage: x = OrderedTree([[],[[]]])
501
+ sage: with x.clone() as x:
502
+ ... x[0] = OrderedTree([[]])
503
+ sage: x
504
+ [[[]], [[]]]
505
+
506
+ One can also substitute at any depths::
507
+
508
+ sage: y = OrderedTree(x)
509
+ sage: with x.clone() as x:
510
+ ... x[0,0] = OrderedTree([[]])
511
+ sage: x
512
+ [[[[]]], [[]]]
513
+ sage: y
514
+ [[[]], [[]]]
515
+ sage: with y.clone() as y:
516
+ ... y[(0,)] = OrderedTree([])
517
+ sage: y
518
+ [[], [[]]]
519
+
520
+ This works for binary trees as well::
521
+
522
+ sage: bt = BinaryTree([[],[[],[]]]); bt
523
+ [[., .], [[., .], [., .]]]
524
+ sage: with bt.clone() as bt1:
525
+ ... bt1[0,0] = BinaryTree([[[], []], None])
526
+ sage: bt1
527
+ [[[[[., .], [., .]], .], .], [[., .], [., .]]]
528
+
529
+ TESTS::
530
+
531
+ sage: x = OrderedTree([])
532
+ sage: with x.clone() as x:
533
+ ... x[0] = OrderedTree([[]])
534
+ Traceback (most recent call last):
535
+ ...
536
+ IndexError: list assignment index out of range
537
+
538
+ sage: x = OrderedTree([]); x = OrderedTree([x,x]);x = OrderedTree([x,x]); x = OrderedTree([x,x])
539
+ sage: with x.clone() as x:
540
+ ... x[0,0] = OrderedTree()
541
+ sage: x
542
+ [[[], [[], []]], [[[], []], [[], []]]]
543
+ """
544
+ assert isinstance(value, self.__class__)
545
+
546
+ if isinstance(idx, tuple):
547
+ self.__setitem_rec__(idx, 0, value)
548
+ else:
549
+ self._setitem(idx, value)
550
+
551
+ def __setitem_rec__(self, idx, i, value):
552
+ """
553
+ TESTS::
554
+
555
+ sage: x = OrderedTree([[[], []],[[]]])
556
+ sage: with x.clone() as x:
557
+ ... x[0,1] = OrderedTree([[[]]]) # indirect doctest
558
+ sage: x
559
+ [[[], [[[]]]], [[]]]
560
+ """
561
+ if i == len(idx) - 1:
562
+ self._setitem(idx[-1], value)
563
+ else:
564
+ with self[idx[i]].clone() as child:
565
+ child.__setitem_rec__(idx, i+1, value)
566
+ self[idx[i]] = child
567
+
568
+ def __getitem__(self, idx):
569
+ """
570
+ INPUT:
571
+
572
+ - ``idx`` -- a valid path in ``self`` identifying a node
573
+
574
+ ..note::
575
+
576
+ The default implementation here assume that the container of the
577
+ node inherits from
578
+ :class:`~sage.structure.list_clone.ClonableArray`.
579
+
580
+ EXAMPLES::
581
+
582
+ sage: x = OrderedTree([[],[[]]])
583
+ sage: x[1,0]
584
+ []
585
+ sage: x = OrderedTree([[],[[]]])
586
+ sage: x[()]
587
+ [[], [[]]]
588
+ sage: x[(0,)]
589
+ []
590
+ sage: x[0,0]
591
+ Traceback (most recent call last):
592
+ ...
593
+ IndexError: list index out of range
594
+ """
595
+ if isinstance(idx, slice):
596
+ return ClonableArray.__getitem__(self, idx)
597
+ try:
598
+ i = int(idx)
599
+ except TypeError:
600
+ res = self
601
+ # idx is supposed to be an iterable of ints
602
+ for i in idx:
603
+ res = ClonableArray._getitem(res, i)
604
+ return res
605
+ else:
606
+ return ClonableArray._getitem(self, i)
607
+
608
+
609
+class AbstractLabelledTree(AbstractTree):
610
+ """
611
+ Abstract Labelled Tree
612
+
613
+ Typically a class for labelled tree is contructed by inheriting from a
614
+ class for unlabelled trees and :class:`AbstractLabelledTree`
615
+
616
+ .. rubric:: How should this class be extended ?
617
+
618
+ A class extending :class:`AbstractLabelledTree
619
+ <sage.combinat.abstract_tree.AbstractLabelledTree>` should respect the
620
+ following assumptions:
621
+
622
+ * For a labelled tree ``T`` the call ``T.parent().unlabelled_trees()``
623
+ should return a parent for labelled trees of the same kind: for example,
624
+
625
+ - if ``T`` is a binary labelled tree, ``T.parent()`` is
626
+ ``LabelledBinaryTrees()`` and ``T.parent().unlabelled_trees()`` is
627
+ ``BinaryTrees()``
628
+
629
+ - if ``T`` is an ordered labelled tree, ``T.parent()`` is
630
+ ``LabelledOrderedTrees()`` and ``T.parent().unlabelled_trees()`` is
631
+ ``OrderedTrees()``
632
+
633
+ * In the same vein, the class of ``T`` should contains an attribute
634
+ ``_Unlabelled`` which should be the class for the corresponding
635
+ unlabelled trees.
636
+
637
+ .. SEEALSO:: :class:`AbstractTree`
638
+ """
639
+ def __init__(self, parent, children, label = None, check = True):
640
+ """
641
+ TESTS::
642
+
643
+ sage: LabelledOrderedTree([])
644
+ None[]
645
+ sage: LabelledOrderedTree([], 3)
646
+ 3[]
647
+ sage: LT = LabelledOrderedTree
648
+ sage: t = LT([LT([LT([], label=42), LT([], 21)])], label=1)
649
+ sage: t
650
+ 1[None[42[], 21[]]]
651
+ sage: LabelledOrderedTree(OrderedTree([[],[[],[]],[]]))
652
+ None[None[], None[None[], None[]], None[]]
653
+ """
654
+ # We must initialize the label before the subtrees to allows rooted
655
+ # trees canonization. Indeed it needs that ``self``._hash_() is working
656
+ # at the end of the call super(..., self).__init__(...)
657
+ if isinstance(children, self.__class__):
658
+ if label is None:
659
+ self._label = children._label
660
+ else:
661
+ self._label = label
662
+ else:
663
+ self._label = label
664
+ super(AbstractLabelledTree, self).__init__(parent, children, check=check)
665
+
666
+ def _repr_(self):
667
+ """
668
+ Returns the string representation of ``self``
669
+
670
+ TESTS::
671
+
672
+ sage: LabelledOrderedTree([]) # indirect doctest
673
+ None[]
674
+ sage: LabelledOrderedTree([], label=3) # indirect doctest
675
+ 3[]
676
+ sage: LabelledOrderedTree([[],[[]]]) # indirect doctest
677
+ None[None[], None[None[]]]
678
+ sage: LabelledOrderedTree([[],LabelledOrderedTree([[]], label=2)], label=3)
679
+ 3[None[], 2[None[]]]
680
+ """
681
+ return "%s%s"%(self._label, self[:])
682
+
683
+ def label(self, path=None):
684
+ """
685
+ Returns the label of ``self``
686
+
687
+ INPUT:
688
+
689
+ - ``path`` -- None (default) or a path (list or tuple of children index
690
+ in the tree)
691
+
692
+ OUTPUT: the label of the subtree at indexed by ``path``
693
+
694
+ EXAMPLES::
695
+
696
+ sage: t=LabelledOrderedTree([[],[]], label = 3)
697
+ sage: t.label()
698
+ 3
699
+ sage: t[0].label()
700
+ sage: t=LabelledOrderedTree([LabelledOrderedTree([], 5),[]], label = 3)
701
+ sage: t.label()
702
+ 3
703
+ sage: t[0].label()
704
+ 5
705
+ sage: t[1].label()
706
+ sage: t.label([0])
707
+ 5
708
+ """
709
+ if path is None:
710
+ return self._label
711
+ else:
712
+ tr = self
713
+ for i in path:
714
+ tr = tr[i]
715
+ return tr._label
716
+
717
+ def labels(self):
718
+ """
719
+ Returns the list of labels of ``self``
720
+
721
+ EXAMPLES::
722
+
723
+ sage: LT = LabelledOrderedTree
724
+ sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
725
+ sage: t.labels()
726
+ ['a', 'b', 'c']
727
+
728
+ sage: LBT = LabelledBinaryTree
729
+ sage: LBT([LBT([],label=1),LBT([],label=4)],label=2).labels()
730
+ [2, 1, 4]
731
+ """
732
+ return [t.label() for t in self.subtrees()]
733
+
734
+ def leaf_labels(self):
735
+ """
736
+ Returns the list of labels of the leaves of ``self``
737
+
738
+ EXAMPLES::
739
+
740
+ sage: LT = LabelledOrderedTree
741
+ sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
742
+ sage: t.leaf_labels()
743
+ ['b', 'c']
744
+
745
+ sage: LBT = LabelledBinaryTree
746
+ sage: bt = LBT([LBT([],label='b'),LBT([],label='c')],label='a')
747
+ sage: bt.leaf_labels()
748
+ ['b', 'c']
749
+ sage: LBT([], label='1').leaf_labels()
750
+ ['1']
751
+ sage: LBT(None).leaf_labels()
752
+ []
753
+ """
754
+ return [t.label() for t in self.subtrees() if t.node_number()==1]
755
+
756
+ def __eq__(self, other):
757
+ """
758
+ Tests if ``self`` is equal to ``other``
759
+
760
+ TESTS::
761
+
762
+ sage LabelledOrderedTree() == LabelledOrderedTree()
763
+ True
764
+ sage LabelledOrderedTree([]) == LabelledOrderedTree()
765
+ False
766
+ sage: t1 = LabelledOrderedTree([[],[[]]])
767
+ sage: t2 = LabelledOrderedTree([[],[[]]])
768
+ sage: t1 == t2
769
+ True
770
+ sage: t2 = LabelledOrderedTree(t1)
771
+ sage: t1 == t2
772
+ True
773
+ sage: t1 = LabelledOrderedTree([[],[[]]])
774
+ sage: t2 = LabelledOrderedTree([[[]],[]])
775
+ sage: t1 == t2
776
+ False
777
+ """
778
+ return ( super(AbstractLabelledTree, self).__eq__(other) and
779
+ self._label == other._label )
780
+
781
+ def _hash_(self):
782
+ """
783
+ Returns the hash value for ``self``
784
+
785
+ TESTS::
786
+
787
+ sage: t1 = LabelledOrderedTree([[],[[]]], label = 1); t1hash = t1.__hash__()
788
+ sage: LabelledOrderedTree([[],[[]]], label = 1).__hash__() == t1hash
789
+ True
790
+ sage: LabelledOrderedTree([[[]],[]], label = 1).__hash__() == t1hash
791
+ False
792
+ sage: LabelledOrderedTree(t1, label = 1).__hash__() == t1hash
793
+ True
794
+ sage: LabelledOrderedTree([[],[[]]], label = 25).__hash__() == t1hash
795
+ False
796
+ sage: LabelledOrderedTree(t1, label = 25).__hash__() == t1hash
797
+ False
798
+
799
+ sage: LabelledBinaryTree([[],[[],[]]], label = 25).__hash__() #random
800
+ 8544617749928727644
801
+
802
+ We check that the hash value depend on the value of the labels of the
803
+ subtrees::
804
+
805
+ sage: LBT = LabelledBinaryTree
806
+ sage: t1 = LBT([], label = 1)
807
+ sage: t2 = LBT([], label = 2)
808
+ sage: t3 = LBT([], label = 3)
809
+ sage: t12 = LBT([t1, t2], label = "a")
810
+ sage: t13 = LBT([t1, t3], label = "a")
811
+ sage: t12.__hash__() != t13.__hash__()
812
+ True
813
+ """
814
+ return self._UnLabelled._hash_(self) ^ hash(self._label)
815
+
816
+ def shape(self):
817
+ """
818
+ Returns the unlabelled tree associated to ``self``
819
+
820
+ EXAMPLES::
821
+
822
+ sage: t = LabelledOrderedTree([[],[[]]], label = 25).shape(); t
823
+ [[], [[]]]
824
+
825
+ sage: LabelledBinaryTree([[],[[],[]]], label = 25).shape()
826
+ [[., .], [[., .], [., .]]]
827
+
828
+ TESTS::
829
+
830
+ sage: t.parent()
831
+ Ordered trees
832
+ sage: type(t)
833
+ <class 'sage.combinat.ordered_tree.OrderedTrees_all_with_category.element_class'>
834
+ """
835
+ TR = self.parent().unlabelled_trees()
836
+ if not self:
837
+ return TR.leaf()
838
+ else:
839
+ return TR._element_constructor_([i.shape() for i in self])
840
+
841
+ def as_digraph(self):
842
+ """
843
+ Returns a directed graph version of ``self``
844
+
845
+ EXAMPLES::
846
+
847
+ sage: LT=LabelledOrderedTrees()
848
+ sage: ko=LT([LT([],label=6),LT([],label=1)],label=9)
849
+ sage: ko.as_digraph()
850
+ Digraph on 3 vertices
851
+
852
+ sage: t = BinaryTree([[None, None],[[],None]]);
853
+ sage: lt = t.canonical_labelling()
854
+ sage: lt.as_digraph()
855
+ Digraph on 4 vertices
856
+ """
857
+ from sage.graphs.digraph import DiGraph
858
+ resu=dict([[self.label(),
859
+ [t.label() for t in self if not t.is_empty()]]])
860
+ resu=DiGraph(resu)
861
+ for t in self:
862
+ if not t.is_empty():
863
+ resu=resu.union(t.as_digraph())
864
+ return resu
865
+
866
+
867
+class AbstractLabelledClonableTree(AbstractLabelledTree,
868
+ AbstractClonableTree):
869
+ """
870
+ Abstract Labelled Clonable Tree
871
+
872
+ This class take care of modification for the label by the clone protocol.
873
+
874
+ .. note:: Due to the limitation of Cython inheritance, one cannot inherit
875
+ here from :class:`ClonableArray`, because it would prevent us to
876
+ inherit later from :class:`~sage.structure.list_clone.ClonableList`.
877
+ """
878
+ def set_root_label(self, label):
879
+ """
880
+ Sets the label of the root of ``self``
881
+
882
+ INPUT: ``label`` -- any Sage object
883
+
884
+ OUPUT: ``None``, ``self`` is modified in place
885
+
886
+ .. note::
887
+
888
+ ``self`` must be in a mutable state. See
889
+ :mod:`sage.structure.list_clone` for more details about
890
+ mutability.
891
+
892
+ EXAMPLES::
893
+
894
+ sage: t=LabelledOrderedTree([[],[[],[]]])
895
+ sage: t.set_root_label(3)
896
+ Traceback (most recent call last):
897
+ ...
898
+ ValueError: object is immutable; please change a copy instead.
899
+ sage: with t.clone() as t:
900
+ ... t.set_root_label(3)
901
+ sage: t.label()
902
+ 3
903
+ sage: t
904
+ 3[None[], None[None[], None[]]]
905
+
906
+ This also work for binary trees::
907
+
908
+ sage: bt=LabelledBinaryTree([[],[]])
909
+ sage: bt.set_root_label(3)
910
+ Traceback (most recent call last):
911
+ ...
912
+ ValueError: object is immutable; please change a copy instead.
913
+ sage: with bt.clone() as bt:
914
+ ... bt.set_root_label(3)
915
+ sage: bt.label()
916
+ 3
917
+ sage: bt
918
+ 3[None[., .], None[., .]]
919
+
920
+ TESTS::
921
+
922
+ sage: with t.clone() as t:
923
+ ... t[0] = LabelledOrderedTree(t[0], label = 4)
924
+ sage: t
925
+ 3[4[], None[None[], None[]]]
926
+ sage: with t.clone() as t:
927
+ ... t[1,0] = LabelledOrderedTree(t[1,0], label = 42)
928
+ sage: t
929
+ 3[4[], None[42[], None[]]]
930
+ """
931
+ self._require_mutable()
932
+ self._label = label
933
+
934
+ def set_label(self, path, label):
935
+ """
936
+ Changes the label of subtree indexed by ``path`` to ``label``
937
+
938
+ INPUT:
939
+
940
+ - ``path`` -- ``None`` (default) or a path (list or tuple of children
941
+ index in the tree)
942
+
943
+ - ``label`` -- any sage object
944
+
945
+ OUPUT: Nothing, ``self`` is modified in place
946
+
947
+ .. note::
948
+
949
+ ``self`` must be in a mutable state. See
950
+ :mod:`sage.structure.list_clone` for more details about
951
+ mutability.
952
+
953
+ EXAMPLES::
954
+
955
+ sage: t=LabelledOrderedTree([[],[[],[]]])
956
+ sage: t.set_label((0,), 4)
957
+ Traceback (most recent call last):
958
+ ...
959
+ ValueError: object is immutable; please change a copy instead.
960
+ sage: with t.clone() as t:
961
+ ... t.set_label((0,), 4)
962
+ sage: t
963
+ None[4[], None[None[], None[]]]
964
+ sage: with t.clone() as t:
965
+ ... t.set_label((1,0), label = 42)
966
+ sage: t
967
+ None[4[], None[42[], None[]]]
968
+
969
+ .. todo::
970
+
971
+ Do we want to implement the following syntactic sugar::
972
+
973
+ with t.clone() as tt:
974
+ tt.labels[1,2] = 3 ?
975
+ """
976
+ self._require_mutable()
977
+ path = tuple(path)
978
+ if path == ():
979
+ self._label = label
980
+ else:
981
+ with self[path[0]].clone() as child:
982
+ child.set_label(path[1:], label)
983
+ self[path[0]] = child
984
+
985
+ def map_labels(self, f):
986
+ """
987
+ Applies the function `f` to the labels of ``self``
988
+
989
+ This method returns a copy of ``self`` on which the function `f` has
990
+ been applied on all labels (a label `x` is replaced by `f(x)`).
991
+
992
+ EXAMPLES::
993
+
994
+ sage: LT = LabelledOrderedTree
995
+ sage: t = LT([LT([],label=1),LT([],label=7)],label=3); t
996
+ 3[1[], 7[]]
997
+ sage: t.map_labels(lambda z:z+1)
998
+ 4[2[], 8[]]
999
+
1000
+ sage: LBT = LabelledBinaryTree
1001
+ sage: bt = LBT([LBT([],label=1),LBT([],label=4)],label=2); bt
1002
+ 2[1[., .], 4[., .]]
1003
+ sage: bt.map_labels(lambda z:z+1)
1004
+ 3[2[., .], 5[., .]]
1005
+ """
1006
+ if self.is_empty():
1007
+ return self
1008
+ return self.parent()([t.map_labels(f) for t in self],
1009
+ label=f(self.label()))
1010
diff --git a/sage/combinat/all.py b/sage/combinat/all.py
1011
--- a/sage/combinat/all.py
1012
+++ b/sage/combinat/all.py
1013
@@ -86,6 +86,10 @@ from alternating_sign_matrix import Alte
1014
# Non Decreasing Parking Functions
1015
from non_decreasing_parking_function import NonDecreasingParkingFunctions, NonDecreasingParkingFunction
1016
1017
+from ordered_tree import (OrderedTree, OrderedTrees,
1018
+ LabelledOrderedTree, LabelledOrderedTrees)
1019
+from binary_tree import (BinaryTree, BinaryTrees,
1020
+ LabelledBinaryTree, LabelledBinaryTrees)
1021
1022
from combination import Combinations
1023
from cartesian_product import CartesianProduct
1024
diff --git a/sage/combinat/binary_tree.py b/sage/combinat/binary_tree.py
1025
new file mode 100644
1026
--- /dev/null
1027
+++ b/sage/combinat/binary_tree.py
1028
@@ -0,0 +1,1039 @@
1029
+"""
1030
+Binary trees
1031
+
1032
+This module deals with binary trees as mathematical (in particular immmutable)
1033
+objects.
1034
+
1035
+.. note :: If you need the data-structure for example to represent sets or hash
1036
+ tables with AVL trees, you should have a look at
1037
+ :mod:`sage.misc.sagex_ds`.
1038
+
1039
+On the use of Factories to query a database of counting algorithms
1040
+------------------------------------------------------------------
1041
+
1042
+**The problem we try to solve**
1043
+
1044
+A common problem in combinatorics is to enumerate or count some standard
1045
+mathematical objects satisfying a set of constraints. For instance, one can be
1046
+interested in the :mod:`partitions <sage.combinat.partition>` of an integer `n`
1047
+of length `7` and parts of size at least `3` and at most `8`, [...]
1048
+
1049
+For partitions, the number of different parameters available is actually quite
1050
+large :
1051
+
1052
+- The length of the partition (i.e. partitions in `k` parts, or in "at least"
1053
+ `k_1` parts "at most" `k_2` parts).
1054
+
1055
+- The sum of the partition (i.e. the integer `n`).
1056
+
1057
+- The min/max size of a part, or even a set of integers such that the partition
1058
+ should only use integers from the given set.
1059
+
1060
+- The min/max slope of the partition.
1061
+
1062
+- An inner and outer profile.
1063
+
1064
+- A min/max value for the lexicographical ordering of the partition.
1065
+
1066
+One may in particular be interested in enumerating/counting the partitions
1067
+satisfying *some arbitrary combination* of constraints using the parameters
1068
+listed above.
1069
+
1070
+This all means that there is a real need of unifying a large family of
1071
+algorithms, so that users do not have to find their way through a library
1072
+of 50 different counting/enumeration algorithms *all* dealing with partitions
1073
+with different set of parameters.
1074
+
1075
+**How we solve it**
1076
+
1077
+We try to build a *database* of algorithms that the user can query easily in
1078
+order to use the best implementation for his needs.
1079
+
1080
+Namely, in the case of :mod:`partitions <sage.combinat.partition>`, we want to
1081
+define a class factory named ``Partitions`` and accepting any combination of
1082
+constraints as an input. The role of the ``Partitions`` class factory is in this
1083
+situation to identify the counting/enumeration algorithm corresponding to this
1084
+set of constraint, and to return a hand-made object with the best set of
1085
+methods.
1086
+
1087
+**The design**
1088
+
1089
+For each combination of constraints that has specific enumeration/counting
1090
+algorithms in Sage, we want to create a corresponding class. The result will be
1091
+-- if we stick with the example of partitions -- a brand new Zoo with weird things
1092
+inside :
1093
+
1094
+- ``PartitionsWithFixedSlopeAndOuterProfile(slope, outer_profile)`` --
1095
+ representing the partitions with slope ``slope`` and outer profile
1096
+ ``outer_profile``
1097
+
1098
+- ``PartitionsWithRestrictedPartsAndBoundedLength(part_set, length)`` --
1099
+ represeting the partitions with a set of allowed parts and given length.
1100
+
1101
+- ...
1102
+
1103
+Each of these classes should define methods like ``__iter__`` (so that we can
1104
+iterate on its elements) or ``cardinality``.
1105
+
1106
+The main class ``Partitions`` will then take as arguments *all of the*
1107
+*combinations of parameters the user may like*, and query the database for the
1108
+best secialized class implemented. The user then receives an instance of this
1109
+specialized class that he can use with the best algorithms implemented.
1110
+
1111
+Of course, it may happen that there is actually no algorithm able to enumerate
1112
+partitions with the set of constraints specified. In this case, the best way is
1113
+to build a class enumerating a larger set of partitions, and to check for each
1114
+of them whether is also satisfies the more restrictive set of constraints. This
1115
+is costly, but it is the best way available, and the library should also be able
1116
+to answer the question *"what is the best implementation available to list the
1117
+partitions asked by the user ?"*. We then need to make sure we enumerate as few
1118
+unnecessary elements as possible.
1119
+
1120
+**AUTHORS:**
1121
+
1122
+- Florent Hivert (2010-2011): initial implementation.
1123
+"""
1124
+#*****************************************************************************
1125
+# Copyright (C) 2010 Florent Hivert <[email protected]>,
1126
+#
1127
+# Distributed under the terms of the GNU General Public License (GPL)
1128
+# as published by the Free Software Foundation; either version 2 of
1129
+# the License, or (at your option) any later version.
1130
+# http://www.gnu.org/licenses/
1131
+#*****************************************************************************
1132
+from sage.structure.list_clone import ClonableArray, ClonableList
1133
+from sage.combinat.abstract_tree import (AbstractClonableTree,
1134
+ AbstractLabelledClonableTree)
1135
+from sage.combinat.ordered_tree import LabelledOrderedTrees
1136
+from sage.rings.integer import Integer
1137
+from sage.misc.classcall_metaclass import ClasscallMetaclass
1138
+from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute
1139
+
1140
+class BinaryTree(AbstractClonableTree, ClonableArray):
1141
+ """
1142
+ The class of binary trees
1143
+
1144
+ INPUT:
1145
+
1146
+ - ``children`` -- ``None`` (default) or a list, tuple or iterable of
1147
+ length 2 of binary trees or convertible objects.
1148
+
1149
+ - ``check`` -- (default to ``True``) whether check for binary should be
1150
+ performed or not.
1151
+
1152
+ .. warning:: despite what the HTML documentation may say, ``BinaryTree``
1153
+ does not have any ``parent`` argument, as the examples below
1154
+ show.
1155
+
1156
+ EXAMPLES::
1157
+
1158
+ sage: BinaryTree()
1159
+ .
1160
+ sage: BinaryTree([None, None])
1161
+ [., .]
1162
+ sage: BinaryTree([None, []])
1163
+ [., [., .]]
1164
+ sage: BinaryTree([[], None])
1165
+ [[., .], .]
1166
+ sage: BinaryTree([[], None, []])
1167
+ Traceback (most recent call last):
1168
+ ...
1169
+ AssertionError: This is not a binary tree
1170
+
1171
+ TESTS::
1172
+
1173
+ sage: t1 = BinaryTree([[None, [[],[[], None]]],[[],[]]])
1174
+ sage: t2 = BinaryTree([[[],[]],[]])
1175
+ sage: with t1.clone() as t1c:
1176
+ ... t1c[1,1,1] = t2
1177
+ sage: t1 == t1c
1178
+ False
1179
+ """
1180
+ __metaclass__ = ClasscallMetaclass
1181
+
1182
+ @staticmethod
1183
+ def __classcall_private__(cls, *args, **opts):
1184
+ """
1185
+ Ensure that binary trees created by the enumerated sets and directly
1186
+ are the same and that they are instances of :class:`BinaryTree`
1187
+
1188
+ TESTS::
1189
+
1190
+ sage: from sage.combinat.binary_tree import BinaryTrees_all
1191
+ sage: issubclass(BinaryTrees_all().element_class, BinaryTree)
1192
+ True
1193
+ sage: t0 = BinaryTree([[],[[], None]])
1194
+ sage: t0.parent()
1195
+ Binary trees
1196
+ sage: type(t0)
1197
+ <class 'sage.combinat.binary_tree.BinaryTrees_all_with_category.element_class'>
1198
+
1199
+ sage: t1 = BinaryTrees()([[],[[], None]])
1200
+ sage: t1.parent() is t0.parent()
1201
+ True
1202
+ sage: type(t1) is type(t0)
1203
+ True
1204
+
1205
+ sage: t1 = BinaryTrees(4)([[],[[], None]])
1206
+ sage: t1.parent() is t0.parent()
1207
+ True
1208
+ sage: type(t1) is type(t0)
1209
+ True
1210
+ """
1211
+ return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
1212
+
1213
+ @lazy_class_attribute
1214
+ def _auto_parent(cls):
1215
+ """
1216
+ The automatic parent of the element of this class
1217
+
1218
+ When calling the constructor of an element of this class, one needs a
1219
+ parent. This class attribute specifies which parent is used.
1220
+
1221
+ EXAMPLES::
1222
+
1223
+ sage: BinaryTree._auto_parent
1224
+ Binary trees
1225
+ sage: BinaryTree([None, None]).parent()
1226
+ Binary trees
1227
+ """
1228
+ return BinaryTrees_all()
1229
+
1230
+ def __init__(self, parent, children = None, check=True):
1231
+ """
1232
+ TESTS::
1233
+
1234
+ sage: BinaryTree([None, None]).parent()
1235
+ Binary trees
1236
+ """
1237
+ if children is None:
1238
+ children = []
1239
+ elif children == [] or isinstance(children, (Integer, int)):
1240
+ children = [None, None]
1241
+ if (children.__class__ is self.__class__ and
1242
+ children.parent() == parent):
1243
+ children = list(children)
1244
+ else:
1245
+ children = [self.__class__(parent, x) for x in children]
1246
+ ClonableArray.__init__(self, parent, children, check=check)
1247
+
1248
+ def check(self):
1249
+ """
1250
+ Checks that ``self`` is a binary tree
1251
+
1252
+ EXAMPLES::
1253
+
1254
+ sage: BinaryTree([[], []]) # indirect doctest
1255
+ [[., .], [., .]]
1256
+ sage: BinaryTree([[], [], []]) # indirect doctest
1257
+ Traceback (most recent call last):
1258
+ ...
1259
+ AssertionError: This is not a binary tree
1260
+ sage: BinaryTree([[]]) # indirect doctest
1261
+ Traceback (most recent call last):
1262
+ ...
1263
+ AssertionError: This is not a binary tree
1264
+ """
1265
+ assert (not self or len(self) == 2), "This is not a binary tree"
1266
+
1267
+ def _repr_(self):
1268
+ """
1269
+ TESTS::
1270
+
1271
+ sage: t1 = BinaryTree([[], None]); t1 # indirect doctest
1272
+ [[., .], .]
1273
+ sage: BinaryTree([[None, t1], None]) # indirect doctest
1274
+ [[., [[., .], .]], .]
1275
+ """
1276
+ if not self:
1277
+ return "."
1278
+ else:
1279
+ return super(BinaryTree, self)._repr_()
1280
+
1281
+ def is_empty(self):
1282
+ """
1283
+ Returns whether ``self`` is empty.
1284
+
1285
+ EXAMPLES::
1286
+
1287
+ sage: BinaryTree().is_empty()
1288
+ True
1289
+ sage: BinaryTree([]).is_empty()
1290
+ False
1291
+ sage: BinaryTree([[], None]).is_empty()
1292
+ False
1293
+ """
1294
+ return not self
1295
+
1296
+ def graph(self):
1297
+ """
1298
+ Convert ``self`` to a digraph
1299
+
1300
+ EXAMPLE::
1301
+
1302
+ sage: t1 = BinaryTree([[], None])
1303
+ sage: t1.graph()
1304
+ Digraph on 5 vertices
1305
+
1306
+ sage: t1 = BinaryTree([[], [[], None]])
1307
+ sage: t1.graph()
1308
+ Digraph on 9 vertices
1309
+ sage: t1.graph().edges()
1310
+ [(0, 1, None), (0, 4, None), (1, 2, None), (1, 3, None), (4, 5, None), (4, 8, None), (5, 6, None), (5, 7, None)]
1311
+ """
1312
+ from sage.graphs.graph import DiGraph
1313
+ res = DiGraph()
1314
+ def rec(tr, idx):
1315
+ if not tr:
1316
+ return
1317
+ else:
1318
+ nbl = 2*tr[0].node_number() + 1
1319
+ res.add_edges([[idx,idx+1], [idx,idx+1+nbl]])
1320
+ rec(tr[0], idx + 1)
1321
+ rec(tr[1], idx + nbl + 1)
1322
+ rec(self, 0)
1323
+ return res
1324
+
1325
+ def canonical_labelling(self,shift=1):
1326
+ """
1327
+ Returns a labelled version of ``self``.
1328
+
1329
+ The actual canonical labelling is currently unspecified. However, it
1330
+ is guaranteed to have labels in `1...n` where `n` is the number of
1331
+ node of the tree. Moreover, two (unlabelled) trees compare as equal if
1332
+ and only if they canonical labelled trees compare as equal.
1333
+
1334
+ EXAMPLES::
1335
+
1336
+ sage: BinaryTree().canonical_labelling()
1337
+ .
1338
+ sage: BinaryTree([]).canonical_labelling()
1339
+ 1[., .]
1340
+ sage: BinaryTree([[[], [[], None]], [[], []]]).canonical_labelling()
1341
+ 5[2[1[., .], 4[3[., .], .]], 7[6[., .], 8[., .]]]
1342
+ """
1343
+ LTR = self.parent().labelled_trees()
1344
+ if self:
1345
+ sz0 = self[0].node_number()
1346
+ return LTR([self[0].canonical_labelling(shift),
1347
+ self[1].canonical_labelling(shift+1+sz0)],
1348
+ label=shift+sz0)
1349
+ else:
1350
+ return LTR(None)
1351
+
1352
+ def show(self):
1353
+ """
1354
+ TESTS::
1355
+
1356
+ sage: t1 = BinaryTree([[], [[], None]])
1357
+ sage: t1.show()
1358
+ """
1359
+ self.graph().show(layout='tree', tree_root=0, tree_orientation="down")
1360
+
1361
+ def make_node(self, child_list = [None, None]):
1362
+ """
1363
+ Modify ``self`` so that it becomes a node with children ``childlist``
1364
+
1365
+ INPUT:
1366
+
1367
+ - ``child_list`` -- a pair of binary trees (or objects convertible to)
1368
+
1369
+ .. note:: ``self`` must be in a mutable state.
1370
+
1371
+ .. seealso::
1372
+ :meth:`make_leaf <sage.combinat.binary_tree.BinaryTree.make_leaf>`
1373
+
1374
+ EXAMPLES::
1375
+
1376
+ sage: t = BinaryTree()
1377
+ sage: t.make_node([None, None])
1378
+ Traceback (most recent call last):
1379
+ ...
1380
+ ValueError: object is immutable; please change a copy instead.
1381
+ sage: with t.clone() as t1:
1382
+ ... t1.make_node([None, None])
1383
+ sage: t, t1
1384
+ (., [., .])
1385
+ sage: with t.clone() as t:
1386
+ ... t.make_node([BinaryTree(), BinaryTree(), BinaryTree([])])
1387
+ Traceback (most recent call last):
1388
+ AssertionError: the list must have length 2
1389
+ sage: with t1.clone() as t2:
1390
+ ... t2.make_node([t1, t1])
1391
+ sage: with t2.clone() as t3:
1392
+ ... t3.make_node([t1, t2])
1393
+ sage: t1, t2, t3
1394
+ ([., .], [[., .], [., .]], [[., .], [[., .], [., .]]])
1395
+ """
1396
+ self._require_mutable()
1397
+ child_lst = [self.__class__(self.parent(), x) for x in child_list]
1398
+ assert(len(child_lst) == 2), "the list must have length 2"
1399
+ self.__init__(self.parent(), child_lst, check=False)
1400
+
1401
+ def make_leaf(self):
1402
+ """
1403
+ Modify ``self`` so that it became a leaf
1404
+
1405
+ .. note:: ``self`` must be in a mutable state.
1406
+
1407
+ .. seealso::
1408
+ :meth:`make_node <sage.combinat.binary_tree.BinaryTree.make_node>`
1409
+
1410
+ EXAMPLES::
1411
+
1412
+ sage: t = BinaryTree([None, None])
1413
+ sage: t.make_leaf()
1414
+ Traceback (most recent call last):
1415
+ ...
1416
+ ValueError: object is immutable; please change a copy instead.
1417
+ sage: with t.clone() as t1:
1418
+ ... t1.make_leaf()
1419
+ sage: t, t1
1420
+ ([., .], .)
1421
+ """
1422
+ self._require_mutable()
1423
+ self.__init__(self.parent(), None)
1424
+
1425
+ def _to_dyck_word_rec(self):
1426
+ r"""
1427
+ EXAMPLES::
1428
+
1429
+ sage: BinaryTree()._to_dyck_word_rec()
1430
+ []
1431
+ sage: BinaryTree([])._to_dyck_word_rec()
1432
+ [1, 0]
1433
+ sage: BinaryTree([[[], [[], None]], [[], []]])._to_dyck_word_rec()
1434
+ [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0]
1435
+ """
1436
+ if self:
1437
+ return ([1]+self[0]._to_dyck_word_rec()+
1438
+ [0]+self[1]._to_dyck_word_rec())
1439
+ else:
1440
+ return []
1441
+
1442
+ def to_dyck_word(self):
1443
+ r"""
1444
+ Return the Dyck word associated to ``self``
1445
+
1446
+ The bijection is defined recursively as follows:
1447
+
1448
+ - a leaf is associated to the empty Dyck Word
1449
+
1450
+ - a tree with chidren `l,r` is associated to the Dyck word
1451
+ `1 T(l) 0 T(r)` where `T(l)` and `T(r)` are the trees
1452
+ associated to `l` and `r`.
1453
+
1454
+ EXAMPLES::
1455
+
1456
+ sage: BinaryTree().to_dyck_word()
1457
+ []
1458
+ sage: BinaryTree([]).to_dyck_word()
1459
+ [1, 0]
1460
+ sage: BinaryTree([[[], [[], None]], [[], []]]).to_dyck_word()
1461
+ [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0]
1462
+ """
1463
+ from sage.combinat.dyck_word import DyckWord
1464
+ return DyckWord(self._to_dyck_word_rec())
1465
+
1466
+ def canopee(self):
1467
+ """
1468
+ Returns the canopee of ``self``
1469
+
1470
+ The *canopee* of a non empty binary tree `T` with `n` internal nodes is
1471
+ the list `l` of `0` and `1` of length `n-1` obtained by going along the
1472
+ leaves of `T` from left to right except the two extremal ones, writing
1473
+ `0` if the leaf is a right leaf and `1` is a left leaf.
1474
+
1475
+ EXAMPLES::
1476
+
1477
+ sage: BinaryTree([]).canopee()
1478
+ []
1479
+ sage: BinaryTree([None, []]).canopee()
1480
+ [1]
1481
+ sage: BinaryTree([[], None]).canopee()
1482
+ [0]
1483
+ sage: BinaryTree([[], []]).canopee()
1484
+ [0, 1]
1485
+ sage: BinaryTree([[[], [[], None]], [[], []]]).canopee()
1486
+ [0, 1, 0, 0, 1, 0, 1]
1487
+
1488
+ The number of pairs `(t_1, t_2)` of binary trees of size `n` such that
1489
+ the canopee of `t_1` is the complementary of the canopee of `t_2` is
1490
+ also the number of Baxter permutations (see [DG]_, see also sequences
1491
+ A001181 in Sloane's database). We check this in small cases::
1492
+
1493
+ sage: [len([(u,v) for u in BinaryTrees(n) for v in BinaryTrees(n)
1494
+ ... if map(lambda x:1-x, u.canopee()) == v.canopee()])
1495
+ ... for n in range(1, 5)]
1496
+ [1, 2, 6, 22]
1497
+
1498
+ Here is a less trivial implementation of this::
1499
+
1500
+ sage: from sage.sets.finite_set_map_cy import fibers
1501
+ sage: from sage.misc.all import attrcall
1502
+ sage: def baxter(n):
1503
+ ... f = fibers(lambda t: tuple(t.canopee()),
1504
+ ... BinaryTrees(n))
1505
+ ... return sum(len(f[i])*len(f[tuple(1-x for x in i)])
1506
+ ... for i in f)
1507
+ sage: [baxter(n) for n in range(1, 7)]
1508
+ [1, 2, 6, 22, 92, 422]
1509
+
1510
+ TESTS::
1511
+
1512
+ sage: t = BinaryTree().canopee()
1513
+ Traceback (most recent call last):
1514
+ ...
1515
+ ValueError: canopee is only defined for non empty binary trees
1516
+
1517
+ REFERENCES:
1518
+
1519
+ .. [DG] S. Dulucq and O, Guibert. Mots de piles, tableaux
1520
+ standards et permutations de Baxter, proceedings of
1521
+ Formal Power Series and Algebraic Combinatorics, 1994.
1522
+ """
1523
+ if not self:
1524
+ raise ValueError, "canopee is only defined for non empty binary trees"
1525
+ res = []
1526
+ def add_leaf_rec(tr):
1527
+ for i in range(2):
1528
+ if tr[i]:
1529
+ add_leaf_rec(tr[i])
1530
+ else:
1531
+ res.append(1-i)
1532
+ add_leaf_rec(self)
1533
+ return res[1:-1]
1534
+
1535
+
1536
+from sage.structure.parent import Parent
1537
+from sage.structure.unique_representation import UniqueRepresentation
1538
+from sage.misc.classcall_metaclass import ClasscallMetaclass
1539
+
1540
+from sage.sets.non_negative_integers import NonNegativeIntegers
1541
+from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
1542
+from sage.sets.family import Family
1543
+from sage.misc.cachefunc import cached_method
1544
+
1545
+
1546
+# Abstract class to serve as a Factory no instance are created.
1547
+class BinaryTrees(UniqueRepresentation, Parent):
1548
+ """
1549
+ Factory for binary trees.
1550
+
1551
+ INPUT:
1552
+
1553
+ - ``size`` -- (optional) an integer
1554
+
1555
+ OUPUT:
1556
+
1557
+ - the set of all binary trees (of the given ``size`` if specified)
1558
+
1559
+ EXAMPLES::
1560
+
1561
+ sage: BinaryTrees()
1562
+ Binary trees
1563
+
1564
+ sage: BinaryTrees(2)
1565
+ Binary trees of size 2
1566
+
1567
+ .. note:: this in a factory class whose constructor returns instances of
1568
+ subclasses.
1569
+
1570
+ .. note:: the fact that OrderedTrees is a class instead a simple callable
1571
+ is an implementation detail. It could be changed in the future
1572
+ and one should not rely on it.
1573
+ """
1574
+ @staticmethod
1575
+ def __classcall_private__(cls, n=None):
1576
+ """
1577
+ TESTS::
1578
+
1579
+ sage: from sage.combinat.binary_tree import BinaryTrees_all, BinaryTrees_size
1580
+ sage: isinstance(BinaryTrees(2), BinaryTrees)
1581
+ True
1582
+ sage: isinstance(BinaryTrees(), BinaryTrees)
1583
+ True
1584
+ sage: BinaryTrees(2) is BinaryTrees_size(2)
1585
+ True
1586
+ sage: BinaryTrees(5).cardinality()
1587
+ 42
1588
+ sage: BinaryTrees() is BinaryTrees_all()
1589
+ True
1590
+ """
1591
+ if n is None:
1592
+ return BinaryTrees_all()
1593
+ else:
1594
+ assert (isinstance(n, (Integer, int)) and n >= 0), "n must be a non negative integer"
1595
+ return BinaryTrees_size(Integer(n))
1596
+
1597
+ @cached_method
1598
+ def leaf(self):
1599
+ """
1600
+ Return a left tree with ``self`` as parent.
1601
+
1602
+ EXAMPLES::
1603
+
1604
+ sage: BinaryTrees().leaf()
1605
+ .
1606
+
1607
+ TEST::
1608
+
1609
+ sage: (BinaryTrees().leaf() is
1610
+ ... sage.combinat.binary_tree.BinaryTrees_all().leaf())
1611
+ True
1612
+ """
1613
+ return self(None)
1614
+
1615
+#################################################################
1616
+# Enumerated set of all binary trees
1617
+#################################################################
1618
+class BinaryTrees_all(DisjointUnionEnumeratedSets, BinaryTrees):
1619
+
1620
+ def __init__(self):
1621
+ """
1622
+ TESTS::
1623
+
1624
+ sage: from sage.combinat.binary_tree import BinaryTrees_all
1625
+ sage: B = BinaryTrees_all()
1626
+ sage: B.cardinality()
1627
+ +Infinity
1628
+
1629
+ sage: it = iter(B)
1630
+ sage: (it.next(), it.next(), it.next(), it.next(), it.next())
1631
+ (., [., .], [., [., .]], [[., .], .], [., [., [., .]]])
1632
+ sage: it.next().parent()
1633
+ Binary trees
1634
+ sage: B([])
1635
+ [., .]
1636
+
1637
+ sage: B is BinaryTrees_all()
1638
+ True
1639
+ sage: TestSuite(B).run()
1640
+ """
1641
+ DisjointUnionEnumeratedSets.__init__(
1642
+ self, Family(NonNegativeIntegers(), BinaryTrees_size),
1643
+ facade=True, keepkey = False)
1644
+
1645
+ def _repr_(self):
1646
+ """
1647
+ TEST::
1648
+
1649
+ sage: BinaryTrees() # indirect doctest
1650
+ Binary trees
1651
+ """
1652
+ return "Binary trees"
1653
+
1654
+ def __contains__(self, x):
1655
+ """
1656
+ TESTS::
1657
+
1658
+ sage: S = BinaryTrees()
1659
+ sage: 1 in S
1660
+ False
1661
+ sage: S([]) in S
1662
+ True
1663
+ """
1664
+ return isinstance(x, self.element_class)
1665
+
1666
+ def __call__(self, x=None, *args, **keywords):
1667
+ """
1668
+ Ensure that ``None`` instead of ``0`` is passed by default.
1669
+
1670
+ TESTS::
1671
+
1672
+ sage: B = BinaryTrees()
1673
+ sage: B()
1674
+ .
1675
+ """
1676
+ return super(BinaryTrees, self).__call__(x, *args, **keywords)
1677
+
1678
+ def unlabelled_trees(self):
1679
+ """
1680
+ Returns the set of unlabelled trees associated to ``self``
1681
+
1682
+ EXAMPLES::
1683
+
1684
+ sage: BinaryTrees().unlabelled_trees()
1685
+ Binary trees
1686
+ """
1687
+ return self
1688
+
1689
+ def labelled_trees(self):
1690
+ """
1691
+ Returns the set of labelled trees associated to ``self``
1692
+
1693
+ EXAMPLES::
1694
+
1695
+ sage: BinaryTrees().labelled_trees()
1696
+ Labelled binary trees
1697
+ """
1698
+ return LabelledBinaryTrees()
1699
+
1700
+ def _element_constructor_(self, *args, **keywords):
1701
+ """
1702
+ EXAMPLES::
1703
+
1704
+ sage: B = BinaryTrees()
1705
+ sage: B._element_constructor_([])
1706
+ [., .]
1707
+ sage: B([[],[]]) # indirect doctest
1708
+ [[., .], [., .]]
1709
+ sage: B(None) # indirect doctest
1710
+ .
1711
+ """
1712
+ return self.element_class(self, *args, **keywords)
1713
+
1714
+ Element = BinaryTree
1715
+
1716
+from sage.misc.lazy_attribute import lazy_attribute
1717
+from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
1718
+from combinat import catalan_number
1719
+#################################################################
1720
+# Enumerated set of binary trees of a given size
1721
+#################################################################
1722
+class BinaryTrees_size(BinaryTrees):
1723
+ """
1724
+ The enumerated sets of binary trees of given size
1725
+
1726
+ TESTS::
1727
+
1728
+ sage: from sage.combinat.binary_tree import BinaryTrees_size
1729
+ sage: for i in range(6): TestSuite(BinaryTrees_size(i)).run()
1730
+ """
1731
+ def __init__(self, size):
1732
+ """
1733
+ TESTS::
1734
+
1735
+ sage: S = BinaryTrees(3)
1736
+ sage: S == loads(dumps(S))
1737
+ True
1738
+
1739
+ sage: S is BinaryTrees(3)
1740
+ True
1741
+ """
1742
+ super(BinaryTrees_size, self).__init__(category = FiniteEnumeratedSets())
1743
+ self._size = size
1744
+
1745
+ def _repr_(self):
1746
+ """
1747
+ TESTS::
1748
+
1749
+ sage: BinaryTrees(3) # indirect doctest
1750
+ Binary trees of size 3
1751
+ """
1752
+ return "Binary trees of size %s"%(self._size)
1753
+
1754
+ def __contains__(self, x):
1755
+ """
1756
+ TESTS::
1757
+
1758
+ sage: S = BinaryTrees(3)
1759
+ sage: 1 in S
1760
+ False
1761
+ sage: S([[],[]]) in S
1762
+ True
1763
+ """
1764
+ return isinstance(x, self.element_class) and x.node_number() == self._size
1765
+
1766
+ def _an_element_(self):
1767
+ """
1768
+ TESTS::
1769
+
1770
+ sage: BinaryTrees(0).an_element() # indirect doctest
1771
+ .
1772
+ """
1773
+ return self.first()
1774
+
1775
+ def cardinality(self):
1776
+ """
1777
+ The cardinality of self
1778
+
1779
+ This is a Catalan number.
1780
+
1781
+ TESTS::
1782
+
1783
+ sage: BinaryTrees(0).cardinality()
1784
+ 1
1785
+ sage: BinaryTrees(5).cardinality()
1786
+ 42
1787
+ """
1788
+ return catalan_number(self._size)
1789
+
1790
+ def __iter__(self):
1791
+ """
1792
+ A basic generator.
1793
+
1794
+ .. todo:: could be optimized.
1795
+
1796
+ TESTS::
1797
+
1798
+ sage: BinaryTrees(0).list()
1799
+ [.]
1800
+ sage: BinaryTrees(1).list()
1801
+ [[., .]]
1802
+ sage: BinaryTrees(3).list()
1803
+ [[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]]
1804
+ """
1805
+ if self._size == 0:
1806
+ yield self._element_constructor_()
1807
+ else:
1808
+ for i in range(0, self._size):
1809
+ for lft in self.__class__(i):
1810
+ for rgt in self.__class__(self._size-1-i):
1811
+ yield self._element_constructor_([lft, rgt])
1812
+
1813
+ @lazy_attribute
1814
+ def _parent_for(self):
1815
+ """
1816
+ The parent of the element generated by ``self``
1817
+
1818
+ TESTS::
1819
+
1820
+ sage: S = BinaryTrees(3)
1821
+ sage: S._parent_for
1822
+ Binary trees
1823
+ """
1824
+ return BinaryTrees_all()
1825
+
1826
+ @lazy_attribute
1827
+ def element_class(self):
1828
+ """
1829
+ TESTS::
1830
+
1831
+ sage: S = BinaryTrees(3)
1832
+ sage: S.element_class
1833
+ <class 'sage.combinat.binary_tree.BinaryTrees_all_with_category.element_class'>
1834
+ sage: S.first().__class__ == BinaryTrees().first().__class__
1835
+ True
1836
+ """
1837
+ return self._parent_for.element_class
1838
+
1839
+ def _element_constructor_(self, *args, **keywords):
1840
+ """
1841
+ EXAMPLES::
1842
+
1843
+ sage: S = BinaryTrees(0)
1844
+ sage: S([]) # indirect doctest
1845
+ Traceback (most recent call last):
1846
+ ...
1847
+ ValueError: Wrong number of nodes
1848
+ sage: S(None) # indirect doctest
1849
+ .
1850
+
1851
+ sage: S = BinaryTrees(1) # indirect doctest
1852
+ sage: S([])
1853
+ [., .]
1854
+ """
1855
+ res = self.element_class(self._parent_for, *args, **keywords)
1856
+ if res.node_number() != self._size:
1857
+ raise ValueError, "Wrong number of nodes"
1858
+ return res
1859
+
1860
+
1861
+
1862
+class LabelledBinaryTree(AbstractLabelledClonableTree, BinaryTree):
1863
+ """
1864
+ The class of labelled binary tree
1865
+
1866
+ EXAMPLE::
1867
+
1868
+ sage: LBT = LabelledBinaryTree
1869
+ sage: t1 = LBT([[LBT([], label=2), None], None], label=4); t1
1870
+ 4[None[2[., .], .], .]
1871
+ """
1872
+ __metaclass__ = ClasscallMetaclass
1873
+
1874
+ @staticmethod
1875
+ def __classcall_private__(cls, *args, **opts):
1876
+ """
1877
+ Ensure that trees created by the sets and directly are the same and
1878
+ that they are instance of :class:`LabelledTree`
1879
+
1880
+ TESTS::
1881
+
1882
+ sage: issubclass(LabelledBinaryTrees().element_class, LabelledBinaryTree)
1883
+ True
1884
+ sage: t0 = LabelledBinaryTree([[],[[], None]], label = 3)
1885
+ sage: t0.parent()
1886
+ Labelled binary trees
1887
+ sage: type(t0)
1888
+ <class 'sage.combinat.binary_tree.LabelledBinaryTrees_with_category.element_class'>
1889
+ """
1890
+ return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
1891
+
1892
+ @lazy_class_attribute
1893
+ def _auto_parent(cls):
1894
+ """
1895
+ The automatic parent of the element of this class
1896
+
1897
+ When calling the constructor of an element of this class, one need a
1898
+ parent. This class attribute specifies which parent is used.
1899
+
1900
+ EXAMPLES::
1901
+
1902
+ sage: LabelledBinaryTree._auto_parent
1903
+ Labelled binary trees
1904
+ sage: LabelledBinaryTree([], label = 3).parent()
1905
+ Labelled binary trees
1906
+ """
1907
+ return LabelledBinaryTrees()
1908
+
1909
+ def _repr_(self):
1910
+ """
1911
+ TESTS::
1912
+
1913
+ sage: LBT = LabelledBinaryTree
1914
+ sage: t1 = LBT([[LBT([], label=2), None], None], label=4); t1
1915
+ 4[None[2[., .], .], .]
1916
+ sage: LBT([[],[[], None]], label = 3) # indirect doctest
1917
+ 3[None[., .], None[None[., .], .]]
1918
+ """
1919
+ if not self:
1920
+ if self._label is not None:
1921
+ return repr(self._label)
1922
+ else:
1923
+ return "."
1924
+ else:
1925
+ return "%s%s"%(self._label, self[:])
1926
+
1927
+ def binary_search_insert(self, letter):
1928
+ """
1929
+ Insert a letter in a binary search tree
1930
+
1931
+ INPUT:
1932
+
1933
+ - ``letter`` -- any object comparable with the label of ``self``
1934
+
1935
+ .. note:: ``self`` is supposed to be a binary search tree. No check is
1936
+ performed.
1937
+
1938
+ EXAMPLES::
1939
+
1940
+ sage: LBT = LabelledBinaryTree
1941
+ sage: LBT(None).binary_search_insert(3)
1942
+ 3[., .]
1943
+ sage: LBT([], label = 1).binary_search_insert(3)
1944
+ 1[., 3[., .]]
1945
+ sage: LBT([], label = 3).binary_search_insert(1)
1946
+ 3[1[., .], .]
1947
+ sage: res = LBT(None)
1948
+ sage: for i in [3,1,5,2,4,6]:
1949
+ ... res = res.binary_search_insert(i)
1950
+ sage: res
1951
+ 3[1[., 2[., .]], 5[4[., .], 6[., .]]]
1952
+ """
1953
+ LT = self.parent()._element_constructor_
1954
+ if not self:
1955
+ return LT([], label = letter)
1956
+ else:
1957
+ if letter <= self.label():
1958
+ fils = self[0].binary_search_insert(letter)
1959
+ return LT([fils, self[1]], label=self.label())
1960
+ else:
1961
+ fils = self[1].binary_search_insert(letter)
1962
+ return LT([self[0], fils], label=self.label())
1963
+
1964
+ _UnLabelled = BinaryTree
1965
+
1966
+
1967
+class LabelledBinaryTrees(LabelledOrderedTrees):
1968
+ """
1969
+ This is a parent stub to serve as a factory class for trees with various
1970
+ labels constraints
1971
+ """
1972
+ def _repr_(self):
1973
+ """
1974
+ TESTS::
1975
+
1976
+ sage: LabelledBinaryTrees() # indirect doctest
1977
+ Labelled binary trees
1978
+ """
1979
+ return "Labelled binary trees"
1980
+
1981
+ def _an_element_(self):
1982
+ """
1983
+ Returns a labelled binary tree
1984
+
1985
+ EXAMPLE::
1986
+
1987
+ sage: LabelledBinaryTrees().an_element() # indirect doctest
1988
+ toto[42[3[., .], 3[., .]], 5[None[., .], None[., .]]]
1989
+ """
1990
+ LT = self._element_constructor_
1991
+ t = LT([], label = 3)
1992
+ t1 = LT([t,t], label = 42)
1993
+ t2 = LT([[], []], label = 5)
1994
+ return LT([t1,t2], label = "toto")
1995
+
1996
+ def unlabelled_trees(self):
1997
+ """
1998
+ Returns the set of unlabelled trees associated to ``self``
1999
+
2000
+ EXAMPLES::
2001
+
2002
+ sage: LabelledBinaryTrees().unlabelled_trees()
2003
+ Binary trees
2004
+
2005
+ This is used to compute the shape::
2006
+
2007
+ sage: t = LabelledBinaryTrees().an_element().shape(); t
2008
+ [[[., .], [., .]], [[., .], [., .]]]
2009
+ sage: t.parent()
2010
+ Binary trees
2011
+
2012
+ TESTS::
2013
+
2014
+ sage: t = LabelledBinaryTrees().an_element()
2015
+ sage: t.canonical_labelling()
2016
+ 4[2[1[., .], 3[., .]], 6[5[., .], 7[., .]]]
2017
+ """
2018
+ return BinaryTrees_all()
2019
+
2020
+ def labelled_trees(self):
2021
+ """
2022
+ Returns the set of labelled trees associated to ``self``
2023
+
2024
+ EXAMPLES::
2025
+
2026
+ sage: LabelledBinaryTrees().labelled_trees()
2027
+ Labelled binary trees
2028
+ """
2029
+ return self
2030
+
2031
+ Element = LabelledBinaryTree
2032
+
2033
+
2034
+
2035
+################################################################
2036
+# Interface attempt with species...
2037
+#
2038
+# Kept here for further reference when species will be improved
2039
+################################################################
2040
+# from sage.combinat.species.library import (
2041
+# CombinatorialSpecies, EmptySetSpecies, SingletonSpecies)
2042
+
2043
+# BT = CombinatorialSpecies()
2044
+# F = EmptySetSpecies()
2045
+# N = SingletonSpecies()
2046
+# BT.define(F+N*(BT*BT))
2047
+# # b3 = BT.isotypes(range(3))
2048
+# # tr = b3.list()[1]
2049
+
2050
+# def BTsp_to_bintrees(bt):
2051
+# """
2052
+# sage: from sage.combinat.binary_tree import BT, BTsp_to_bintrees
2053
+# sage: BTsp_to_bintrees(BT.isotypes(range(5))[0])
2054
+# [., [., [., [., [., .]]]]]
2055
+# sage: def spls(size):
2056
+# ... return map(BTsp_to_bintrees, BT.isotypes(range(size)).list())
2057
+# sage: spls(3)
2058
+# [[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]]
2059
+# sage: all(spls(i) == BinaryTrees(i).list() for i in range(5))
2060
+# True
2061
+# """
2062
+# if len(bt) == 0:
2063
+# return BinaryTree()
2064
+# elif len(bt) == 2 and len(bt[1]) == 2:
2065
+# return BinaryTree(map(BTsp_to_bintrees, list(bt[1])))
2066
+# else:
2067
+# raise ValueError
2068
diff --git a/sage/combinat/ordered_tree.py b/sage/combinat/ordered_tree.py
2069
new file mode 100644
2070
--- /dev/null
2071
+++ b/sage/combinat/ordered_tree.py
2072
@@ -0,0 +1,748 @@
2073
+"""
2074
+Ordered Rooted Trees
2075
+
2076
+AUTHORS:
2077
+
2078
+- Florent Hivert (2010-2011): initial revision
2079
+- Frederic Chapoton (2010): contributed some methods
2080
+"""
2081
+#*****************************************************************************
2082
+# Copyright (C) 2010 Florent Hivert <[email protected]>,
2083
+#
2084
+# Distributed under the terms of the GNU General Public License (GPL)
2085
+# as published by the Free Software Foundation; either version 2 of
2086
+# the License, or (at your option) any later version.
2087
+# http://www.gnu.org/licenses/
2088
+#*****************************************************************************
2089
+from sage.structure.list_clone import ClonableArray, ClonableList
2090
+from sage.structure.parent import Parent
2091
+from sage.structure.unique_representation import UniqueRepresentation
2092
+from sage.misc.classcall_metaclass import ClasscallMetaclass
2093
+from sage.misc.lazy_attribute import lazy_class_attribute
2094
+from sage.combinat.abstract_tree import (AbstractClonableTree,
2095
+ AbstractLabelledClonableTree)
2096
+
2097
+class OrderedTree(AbstractClonableTree, ClonableList):
2098
+ """
2099
+ The class for (ordered rooted) Trees
2100
+
2101
+ An ordered tree is a constructed from a node called the root on which one
2102
+ has grafted a possibly empty list of trees. There is a total order on the
2103
+ children of a node which is given by the the order of the element in the
2104
+ list. Note that there is no empty ordered tree.
2105
+
2106
+ One can create a tree from any list (or more generally iterable) of trees
2107
+ or objects convertible to a tree.
2108
+
2109
+ EXAMPLES::
2110
+
2111
+ sage: x = OrderedTree([])
2112
+ sage: x1 = OrderedTree([x,x])
2113
+ sage: x2 = OrderedTree([[],[]])
2114
+ sage: x1 == x2
2115
+ True
2116
+ sage: tt1 = OrderedTree([x,x1,x2])
2117
+ sage: tt2 = OrderedTree([[], [[], []], x2])
2118
+ sage: tt1 == tt2
2119
+ True
2120
+
2121
+ sage: OrderedTree([]) == OrderedTree()
2122
+ True
2123
+
2124
+ TESTS::
2125
+
2126
+ sage: x1.__hash__() == x2.__hash__()
2127
+ True
2128
+ sage: tt1.__hash__() == tt2.__hash__()
2129
+ True
2130
+
2131
+ Trees are usually immutable. However they inherits from
2132
+ :class:`sage.structure.list_clone.ClonableList`. So that they can be
2133
+ modified using the clone protocol:
2134
+
2135
+ Trying to modify a non mutable tree raise an error::
2136
+
2137
+ sage: tt1[1] = tt2
2138
+ Traceback (most recent call last):
2139
+ ...
2140
+ ValueError: object is immutable; please change a copy instead.
2141
+
2142
+ Here is the correct way to do it::
2143
+
2144
+ sage: with tt2.clone() as tt2:
2145
+ ... tt2[1] = tt1
2146
+ sage: tt2
2147
+ [[], [[], [[], []], [[], []]], [[], []]]
2148
+
2149
+ It is also possible to append a child to a tree::
2150
+
2151
+ sage: with tt2.clone() as tt3:
2152
+ ... tt3.append(OrderedTree([]))
2153
+ sage: tt3
2154
+ [[], [[], [[], []], [[], []]], [[], []], []]
2155
+
2156
+ Or to insert a child in a tree::
2157
+
2158
+ sage: with tt2.clone() as tt3:
2159
+ ... tt3.insert(2, OrderedTree([]))
2160
+ sage: tt3
2161
+ [[], [[], [[], []], [[], []]], [], [[], []]]
2162
+
2163
+ We check that ``tt1`` is not modified and that everything is correct with
2164
+ respect to equality::
2165
+
2166
+ sage: tt1
2167
+ [[], [[], []], [[], []]]
2168
+ sage: tt1 == tt2
2169
+ False
2170
+ sage: tt1.__hash__() == tt2.__hash__()
2171
+ False
2172
+
2173
+ TESTS::
2174
+
2175
+ sage: tt1bis = OrderedTree(tt1)
2176
+ sage: with tt1.clone() as tt1:
2177
+ ... tt1[1] = tt1bis
2178
+ sage: tt1
2179
+ [[], [[], [[], []], [[], []]], [[], []]]
2180
+ sage: tt1 == tt2
2181
+ True
2182
+ sage: tt1.__hash__() == tt2.__hash__()
2183
+ True
2184
+ sage: len(tt1)
2185
+ 3
2186
+ sage: tt1[2]
2187
+ [[], []]
2188
+ sage: tt1[3]
2189
+ Traceback (most recent call last):
2190
+ ...
2191
+ IndexError: list index out of range
2192
+ sage: tt1[1:2]
2193
+ [[[], [[], []], [[], []]]]
2194
+
2195
+ Various tests involving construction, equality and hashing::
2196
+
2197
+ sage: OrderedTree() == OrderedTree()
2198
+ True
2199
+ sage: t1 = OrderedTree([[],[[]]])
2200
+ sage: t2 = OrderedTree([[],[[]]])
2201
+ sage: t1 == t2
2202
+ True
2203
+ sage: t2 = OrderedTree(t1)
2204
+ sage: t1 == t2
2205
+ True
2206
+ sage: t1 = OrderedTree([[],[[]]])
2207
+ sage: t2 = OrderedTree([[[]],[]])
2208
+ sage: t1 == t2
2209
+ False
2210
+
2211
+ sage: t1 = OrderedTree([[],[[]]])
2212
+ sage: t2 = OrderedTree([[],[[]]])
2213
+ sage: t1.__hash__() == t2.__hash__()
2214
+ True
2215
+ sage: t2 = OrderedTree([[[]],[]])
2216
+ sage: t1.__hash__() == t2.__hash__()
2217
+ False
2218
+ sage: OrderedTree().__hash__() == OrderedTree([]).__hash__()
2219
+ True
2220
+ sage: tt1 = OrderedTree([t1,t2,t1])
2221
+ sage: tt2 = OrderedTree([t1, [[[]],[]], t1])
2222
+ sage: tt1.__hash__() == tt2.__hash__()
2223
+ True
2224
+
2225
+ Check that the hash value is correctly updated after modification::
2226
+
2227
+ sage: with tt2.clone() as tt2:
2228
+ ... tt2[1,1] = tt1
2229
+ sage: tt1.__hash__() == tt2.__hash__()
2230
+ False
2231
+ """
2232
+
2233
+ __metaclass__ = ClasscallMetaclass
2234
+
2235
+ @staticmethod
2236
+ def __classcall_private__(cls, *args, **opts):
2237
+ """
2238
+ Ensure that trees created by the enumerated sets and directly
2239
+ are the same and that they are instance of :class:`OrderedTree`
2240
+
2241
+ TESTS::
2242
+
2243
+ sage: issubclass(OrderedTrees().element_class, OrderedTree)
2244
+ True
2245
+ sage: t0 = OrderedTree([[],[[], []]])
2246
+ sage: t0.parent()
2247
+ Ordered trees
2248
+ sage: type(t0)
2249
+ <class 'sage.combinat.ordered_tree.OrderedTrees_all_with_category.element_class'>
2250
+
2251
+ sage: t1 = OrderedTrees()([[],[[], []]])
2252
+ sage: t1.parent() is t0.parent()
2253
+ True
2254
+ sage: type(t1) is type(t0)
2255
+ True
2256
+
2257
+ sage: t1 = OrderedTrees(4)([[],[[]]])
2258
+ sage: t1.parent() is t0.parent()
2259
+ True
2260
+ sage: type(t1) is type(t0)
2261
+ True
2262
+ """
2263
+ return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
2264
+
2265
+ @lazy_class_attribute
2266
+ def _auto_parent(cls):
2267
+ """
2268
+ The automatic parent of the element of this class
2269
+
2270
+ When calling the constructor of an element of this class, one need a
2271
+ parent. This class attribute specifies which parent is used.
2272
+
2273
+ EXAMPLES::
2274
+
2275
+ sage: OrderedTree([[],[[]]])._auto_parent
2276
+ Ordered trees
2277
+ sage: OrderedTree([[],[[]]]).parent()
2278
+ Ordered trees
2279
+
2280
+ .. note::
2281
+
2282
+ It is possible to bypass the automatic parent mechanism using:
2283
+
2284
+ sage: t1 = OrderedTree.__new__(OrderedTree, Parent(), [])
2285
+ sage: t1.__init__(Parent(), [])
2286
+ sage: t1
2287
+ []
2288
+ sage: t1.parent()
2289
+ <type 'sage.structure.parent.Parent'>
2290
+ """
2291
+ return OrderedTrees_all()
2292
+
2293
+ def __init__(self, parent=None, children=[], check=True):
2294
+ """
2295
+ TESTS::
2296
+
2297
+ sage: t1 = OrderedTrees(4)([[],[[]]])
2298
+ sage: TestSuite(t1).run()
2299
+ """
2300
+ if (children.__class__ is self.__class__ and
2301
+ children.parent() == parent):
2302
+ children = list(children)
2303
+ else:
2304
+ children = [self.__class__(parent, x) for x in children]
2305
+ ClonableArray.__init__(self, parent, children, check=check)
2306
+
2307
+ def is_empty(self):
2308
+ """
2309
+ Return if ``self`` is the empty tree
2310
+
2311
+ For ordered trees, returns always ``False``
2312
+
2313
+ .. note:: this is different from ``bool(t)`` which returns whether
2314
+ ``t`` has some child or not.
2315
+
2316
+ EXAMPLES::
2317
+
2318
+ sage: t = OrderedTrees(4)([[],[[]]])
2319
+ sage: t.is_empty()
2320
+ False
2321
+ sage: bool(t)
2322
+ True
2323
+ """
2324
+ return False
2325
+
2326
+from sage.categories.sets_cat import Sets, EmptySetError
2327
+from sage.rings.integer import Integer
2328
+from sage.sets.non_negative_integers import NonNegativeIntegers
2329
+from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
2330
+from sage.sets.family import Family
2331
+from sage.misc.cachefunc import cached_method
2332
+
2333
+# Abstract class to serve as a Factory no instance are created.
2334
+class OrderedTrees(UniqueRepresentation, Parent):
2335
+ """
2336
+ Factory for ordered trees
2337
+
2338
+ INPUT:
2339
+
2340
+ - ``size`` -- (optional) an integer
2341
+
2342
+ OUPUT:
2343
+
2344
+ - the set of all ordered trees (of the given ``size`` if specified)
2345
+
2346
+ EXAMPLES::
2347
+
2348
+ sage: OrderedTrees()
2349
+ Ordered trees
2350
+
2351
+ sage: OrderedTrees(2)
2352
+ Ordered trees of size 2
2353
+
2354
+ .. note:: this in a factory class whose constructor returns instances of
2355
+ subclasses.
2356
+
2357
+ .. note:: the fact that OrderedTrees is a class instead a simple callable
2358
+ is an implementation detail. It could be changed in the future
2359
+ and one should not rely on it.
2360
+ """
2361
+ @staticmethod
2362
+ def __classcall_private__(cls, n=None):
2363
+ """
2364
+ TESTS::
2365
+
2366
+ sage: from sage.combinat.ordered_tree import OrderedTrees_all, OrderedTrees_size
2367
+ sage: isinstance(OrderedTrees(2), OrderedTrees)
2368
+ True
2369
+ sage: isinstance(OrderedTrees(), OrderedTrees)
2370
+ True
2371
+ sage: OrderedTrees(2) is OrderedTrees_size(2)
2372
+ True
2373
+ sage: OrderedTrees(5).cardinality()
2374
+ 14
2375
+ sage: OrderedTrees() is OrderedTrees_all()
2376
+ True
2377
+ """
2378
+ if n is None:
2379
+ return OrderedTrees_all()
2380
+ else:
2381
+ assert (isinstance(n, (Integer, int)) and n >= 0), "n must be a non negative integer"
2382
+ return OrderedTrees_size(Integer(n))
2383
+
2384
+ @cached_method
2385
+ def leaf(self):
2386
+ """
2387
+ Return a leaf tree with ``self`` as parent
2388
+
2389
+ EXAMPLES::
2390
+
2391
+ sage: OrderedTrees().leaf()
2392
+ []
2393
+
2394
+ TEST::
2395
+
2396
+ sage: (OrderedTrees().leaf() is
2397
+ ... sage.combinat.ordered_tree.OrderedTrees_all().leaf())
2398
+ True
2399
+ """
2400
+ return self([])
2401
+
2402
+class OrderedTrees_all(DisjointUnionEnumeratedSets, OrderedTrees):
2403
+ """
2404
+ The set of all ordered trees
2405
+
2406
+ EXAMPLES::
2407
+
2408
+ sage: OT = OrderedTrees(); OT
2409
+ Ordered trees
2410
+ sage: OT.cardinality()
2411
+ +Infinity
2412
+ """
2413
+
2414
+ def __init__(self):
2415
+ """
2416
+ TESTS::
2417
+
2418
+ sage: from sage.combinat.ordered_tree import OrderedTrees_all
2419
+ sage: B = OrderedTrees_all()
2420
+ sage: B.cardinality()
2421
+ +Infinity
2422
+
2423
+ sage: it = iter(B)
2424
+ sage: (it.next(), it.next(), it.next(), it.next(), it.next())
2425
+ ([], [[]], [[], []], [[[]]], [[], [], []])
2426
+ sage: it.next().parent()
2427
+ Ordered trees
2428
+ sage: B([])
2429
+ []
2430
+
2431
+ sage: B is OrderedTrees_all()
2432
+ True
2433
+ sage: TestSuite(B).run()
2434
+ """
2435
+ DisjointUnionEnumeratedSets.__init__(
2436
+ self, Family(NonNegativeIntegers(), OrderedTrees_size),
2437
+ facade=True, keepkey=False)
2438
+
2439
+ def _repr_(self):
2440
+ """
2441
+ TEST::
2442
+
2443
+ sage: OrderedTrees() # indirect doctest
2444
+ Ordered trees
2445
+ """
2446
+ return "Ordered trees"
2447
+
2448
+ def __contains__(self, x):
2449
+ """
2450
+ TESTS::
2451
+
2452
+ sage: T = OrderedTrees()
2453
+ sage: 1 in T
2454
+ False
2455
+ sage: T([]) in T
2456
+ True
2457
+ """
2458
+ return isinstance(x, self.element_class)
2459
+
2460
+ def unlabelled_trees(self):
2461
+ """
2462
+ Returns the set of unlabelled trees associated to ``self``
2463
+
2464
+ EXAMPLES::
2465
+
2466
+ sage: OrderedTrees().unlabelled_trees()
2467
+ Ordered trees
2468
+ """
2469
+ return self
2470
+
2471
+ def labelled_trees(self):
2472
+ """
2473
+ Returns the set of unlabelled trees associated to ``self``
2474
+
2475
+ EXAMPLES::
2476
+
2477
+ sage: OrderedTrees().labelled_trees()
2478
+ Labelled ordered trees
2479
+ """
2480
+ return LabelledOrderedTrees()
2481
+
2482
+ def _element_constructor_(self, *args, **keywords):
2483
+ """
2484
+ EXAMPLES::
2485
+
2486
+ sage: T = OrderedTrees()
2487
+ sage: T([]) # indirect doctest
2488
+ []
2489
+ """
2490
+ return self.element_class(self, *args, **keywords)
2491
+
2492
+ Element = OrderedTree
2493
+
2494
+
2495
+
2496
+from sage.misc.lazy_attribute import lazy_attribute
2497
+from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
2498
+from combinat import catalan_number
2499
+from sage.combinat.composition import Compositions
2500
+from sage.combinat.cartesian_product import CartesianProduct
2501
+#################################################################
2502
+# Enumerated set of binary trees of a given size
2503
+#################################################################
2504
+class OrderedTrees_size(OrderedTrees):
2505
+ """
2506
+ The enumerated sets of binary trees of a given size
2507
+
2508
+ EXAMPLES::
2509
+
2510
+ sage: S = OrderedTrees(3); S
2511
+ Ordered trees of size 3
2512
+ sage: S.cardinality()
2513
+ 2
2514
+ sage: S.list()
2515
+ [[[], []], [[[]]]]
2516
+ """
2517
+ def __init__(self, size):
2518
+ """
2519
+ TESTS::
2520
+
2521
+ sage: from sage.combinat.ordered_tree import OrderedTrees_size
2522
+ sage: TestSuite(OrderedTrees_size(0)).run()
2523
+ sage: for i in range(6): TestSuite(OrderedTrees_size(i)).run()
2524
+ """
2525
+ super(OrderedTrees_size, self).__init__(category = FiniteEnumeratedSets())
2526
+ self._size = size
2527
+
2528
+ def _repr_(self):
2529
+ """
2530
+ TESTS::
2531
+
2532
+ sage: OrderedTrees(3) # indirect doctest
2533
+ Ordered trees of size 3
2534
+ """
2535
+ return "Ordered trees of size %s"%(self._size)
2536
+
2537
+ def __contains__(self, x):
2538
+ """
2539
+ TESTS::
2540
+
2541
+ sage: T = OrderedTrees(3)
2542
+ sage: 1 in T
2543
+ False
2544
+ sage: T([[],[]]) in T
2545
+ True
2546
+ """
2547
+ return isinstance(x, self.element_class) and x.node_number() == self._size
2548
+
2549
+ def _an_element_(self):
2550
+ """
2551
+ TESTS::
2552
+
2553
+ sage: OrderedTrees(3).an_element() # indirect doctest
2554
+ [[], []]
2555
+ """
2556
+ if self._size == 0:
2557
+ raise EmptySetError
2558
+ return self.first()
2559
+
2560
+ def cardinality(self):
2561
+ """
2562
+ The cardinality of ``self``
2563
+
2564
+ This is a Catalan number
2565
+
2566
+ TESTS::
2567
+
2568
+ sage: OrderedTrees(0).cardinality()
2569
+ 0
2570
+ sage: OrderedTrees(1).cardinality()
2571
+ 1
2572
+ sage: OrderedTrees(6).cardinality()
2573
+ 42
2574
+ """
2575
+ if self._size == 0:
2576
+ return Integer(0)
2577
+ else:
2578
+ return catalan_number(self._size-1)
2579
+
2580
+ def __iter__(self):
2581
+ """
2582
+ A basic generator
2583
+
2584
+ .. todo:: could be optimized.
2585
+
2586
+ TESTS::
2587
+
2588
+ sage: OrderedTrees(0).list()
2589
+ []
2590
+ sage: OrderedTrees(1).list()
2591
+ [[]]
2592
+ sage: OrderedTrees(2).list()
2593
+ [[[]]]
2594
+ sage: OrderedTrees(3).list()
2595
+ [[[], []], [[[]]]]
2596
+ sage: OrderedTrees(4).list()
2597
+ [[[], [], []], [[], [[]]], [[[]], []], [[[], []]], [[[[]]]]]
2598
+ """
2599
+ if self._size == 0:
2600
+ return
2601
+ else:
2602
+ for c in Compositions(self._size-1):
2603
+ for lst in CartesianProduct(*(map(self.__class__, c))):
2604
+ yield self._element_constructor_(lst)
2605
+
2606
+ @lazy_attribute
2607
+ def _parent_for(self):
2608
+ """
2609
+ Return the parent of the element generated by ``self``
2610
+
2611
+ TESTS::
2612
+
2613
+ sage: OrderedTrees(3)._parent_for
2614
+ Ordered trees
2615
+ """
2616
+ return OrderedTrees_all()
2617
+
2618
+ @lazy_attribute
2619
+ def element_class(self):
2620
+ """
2621
+ The class of the element of ``self``
2622
+
2623
+ EXAMPLES::
2624
+
2625
+ sage: from sage.combinat.ordered_tree import OrderedTrees_size, OrderedTrees_all
2626
+ sage: S = OrderedTrees_size(3)
2627
+ sage: S.element_class is OrderedTrees().element_class
2628
+ True
2629
+ sage: S.first().__class__ == OrderedTrees_all().first().__class__
2630
+ True
2631
+ """
2632
+ return self._parent_for.element_class
2633
+
2634
+ def _element_constructor_(self, *args, **keywords):
2635
+ """
2636
+ EXAMPLES::
2637
+
2638
+ sage: S = OrderedTrees(0)
2639
+ sage: S([]) # indirect doctest
2640
+ Traceback (most recent call last):
2641
+ ...
2642
+ ValueError: Wrong number of nodes
2643
+
2644
+ sage: S = OrderedTrees(1) # indirect doctest
2645
+ sage: S([])
2646
+ []
2647
+ """
2648
+ res = self.element_class(self._parent_for, *args, **keywords)
2649
+ if res.node_number() != self._size:
2650
+ raise ValueError, "Wrong number of nodes"
2651
+ return res
2652
+
2653
+
2654
+class LabelledOrderedTree(AbstractLabelledClonableTree, OrderedTree):
2655
+ """
2656
+ Labelled ordered trees
2657
+
2658
+ A labellel ordered tree is an ordered tree with a label attached at each
2659
+ node
2660
+
2661
+ INPUT:
2662
+
2663
+ - ``children`` -- a list or tuple or more generally any iterable
2664
+ of trees or object convertible to trees
2665
+ - ``label`` -- any Sage object default to ``None``
2666
+
2667
+ EXAMPLES::
2668
+
2669
+ sage: x = LabelledOrderedTree([], label = 3); x
2670
+ 3[]
2671
+ sage: LabelledOrderedTree([x, x, x], label = 2)
2672
+ 2[3[], 3[], 3[]]
2673
+ sage: LabelledOrderedTree((x, x, x), label = 2)
2674
+ 2[3[], 3[], 3[]]
2675
+ sage: LabelledOrderedTree([[],[[], []]], label = 3)
2676
+ 3[None[], None[None[], None[]]]
2677
+ """
2678
+ __metaclass__ = ClasscallMetaclass
2679
+
2680
+ @staticmethod
2681
+ def __classcall_private__(cls, *args, **opts):
2682
+ """
2683
+ Ensure that trees created by the sets and directly are the same and
2684
+ that they are instance of :class:`LabelledOrderedTree`
2685
+
2686
+ TESTS::
2687
+
2688
+ sage: issubclass(LabelledOrderedTrees().element_class, LabelledOrderedTree)
2689
+ True
2690
+ sage: t0 = LabelledOrderedTree([[],[[], []]], label = 3)
2691
+ sage: t0.parent()
2692
+ Labelled ordered trees
2693
+ sage: type(t0)
2694
+ <class 'sage.combinat.ordered_tree.LabelledOrderedTrees_with_category.element_class'>
2695
+ """
2696
+ return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
2697
+
2698
+ @lazy_class_attribute
2699
+ def _auto_parent(cls):
2700
+ """
2701
+ The automatic parent of the element of this class
2702
+
2703
+ When calling the constructor of an element of this class, one need a
2704
+ parent. This class attribute specifies which parent is used.
2705
+
2706
+ EXAMPLES::
2707
+
2708
+ sage: LabelledOrderedTree._auto_parent
2709
+ Labelled ordered trees
2710
+ sage: LabelledOrderedTree([], label = 3).parent()
2711
+ Labelled ordered trees
2712
+ """
2713
+ return LabelledOrderedTrees()
2714
+
2715
+ _UnLabelled = OrderedTree
2716
+
2717
+
2718
+from sage.rings.infinity import Infinity
2719
+class LabelledOrderedTrees(UniqueRepresentation, Parent):
2720
+ """
2721
+ This is a parent stub to serve as a factory class for trees with various
2722
+ labels constraints
2723
+
2724
+ EXAMPLES::
2725
+
2726
+ sage: LOT = LabelledOrderedTrees(); LOT
2727
+ Labelled ordered trees
2728
+ sage: x = LOT([], label = 3); x
2729
+ 3[]
2730
+ sage: x.parent() is LOT
2731
+ True
2732
+ sage: y = LOT([x, x, x], label = 2); y
2733
+ 2[3[], 3[], 3[]]
2734
+ sage: y.parent() is LOT
2735
+ True
2736
+ """
2737
+ def __init__(self, category=None):
2738
+ """
2739
+ TESTS::
2740
+
2741
+ sage: TestSuite(LabelledOrderedTrees()).run()
2742
+ """
2743
+ if category is None:
2744
+ category = Sets()
2745
+ Parent.__init__(self, category = category)
2746
+
2747
+ def _repr_(self):
2748
+ """
2749
+ TESTS::
2750
+
2751
+ sage: LabelledOrderedTrees() # indirect doctest
2752
+ Labelled ordered trees
2753
+ """
2754
+ return "Labelled ordered trees"
2755
+
2756
+ def cardinality(self):
2757
+ """
2758
+ Returns the cardinality of `self`
2759
+
2760
+ EXAMPLE::
2761
+
2762
+ sage: LabelledOrderedTrees().cardinality()
2763
+ +Infinity
2764
+ """
2765
+ return Infinity
2766
+
2767
+ def _an_element_(self):
2768
+ """
2769
+ Returns a labelled tree
2770
+
2771
+ EXAMPLE::
2772
+
2773
+ sage: LabelledOrderedTrees().an_element() # indirect doctest
2774
+ toto[3[], 42[3[], 3[]], 5[None[]]]
2775
+ """
2776
+ LT = self._element_constructor_
2777
+ t = LT([], label = 3)
2778
+ t1 = LT([t,t], label = 42)
2779
+ t2 = LT([[]], label = 5)
2780
+ return LT([t,t1,t2], label = "toto")
2781
+
2782
+ def _element_constructor_(self, *args, **keywords):
2783
+ """
2784
+ EXAMPLES::
2785
+
2786
+ sage: T = LabelledOrderedTrees()
2787
+ sage: T([], label=2) # indirect doctest
2788
+ 2[]
2789
+ """
2790
+ return self.element_class(self, *args, **keywords)
2791
+
2792
+ def unlabelled_trees(self):
2793
+ """
2794
+ Returns the set of unlabelled trees associated to ``self``
2795
+
2796
+ EXAMPLES::
2797
+
2798
+ sage: LabelledOrderedTrees().unlabelled_trees()
2799
+ Ordered trees
2800
+ """
2801
+ return OrderedTrees_all()
2802
+
2803
+ def labelled_trees(self):
2804
+ """
2805
+ Returns the set of labelled trees associated to ``self``
2806
+
2807
+ EXAMPLES::
2808
+
2809
+ sage: LabelledOrderedTrees().labelled_trees()
2810
+ Labelled ordered trees
2811
+ sage: LOT = LabelledOrderedTrees()
2812
+ sage: x = LOT([], label = 3)
2813
+ sage: y = LOT([x, x, x], label = 2)
2814
+ sage: y.canonical_labelling()
2815
+ 1[2[], 3[], 4[]]
2816
+ """
2817
+ return self
2818
+
2819
+ Element = LabelledOrderedTree
2820
+
2821
diff --git a/sage/combinat/permutation.py b/sage/combinat/permutation.py
2822
--- a/sage/combinat/permutation.py
2823
+++ b/sage/combinat/permutation.py
2824
@@ -2930,6 +2930,68 @@ class Permutation_class(CombinatorialObj
2825
"""
2826
return RSK(self)[1]
2827
2828
+ def increasing_tree(self, compare=min):
2829
+ """
2830
+ Return the increasing tree associated to ``self``
2831
+
2832
+ EXAMPLES::
2833
+
2834
+ sage: Permutation([1,4,3,2]).increasing_tree()
2835
+ 1[., 2[3[4[., .], .], .]]
2836
+ sage: Permutation([4,1,3,2]).increasing_tree()
2837
+ 1[4[., .], 2[3[., .], .]]
2838
+
2839
+ By passing the option ``compare=max`` one can have the decreasing
2840
+ tree instead::
2841
+
2842
+ sage: Permutation([2,3,4,1]).increasing_tree(max)
2843
+ 4[3[2[., .], .], 1[., .]]
2844
+ sage: Permutation([2,3,1,4]).increasing_tree(max)
2845
+ 4[3[2[., .], 1[., .]], .]
2846
+ """
2847
+ from sage.combinat.binary_tree import LabelledBinaryTree as LBT
2848
+ def rec(perm):
2849
+ if len(perm) == 0: return LBT(None)
2850
+ mn = compare(perm)
2851
+ k = perm.index(mn)
2852
+ return LBT([rec(perm[:k]), rec(perm[k+1:])], label = mn)
2853
+ return rec(self)
2854
+
2855
+ def binary_search_tree(self, left_to_right=True):
2856
+ """
2857
+ Return the binary search tree associated to ``self``
2858
+
2859
+ EXAMPLES::
2860
+
2861
+ sage: Permutation([1,4,3,2]).binary_search_tree()
2862
+ 1[., 4[3[2[., .], .], .]]
2863
+ sage: Permutation([4,1,3,2]).binary_search_tree()
2864
+ 4[1[., 3[2[., .], .]], .]
2865
+
2866
+ By passing the option ``compare=max`` one can have the decreasing
2867
+ tree instead::
2868
+
2869
+ sage: Permutation([1,4,3,2]).binary_search_tree(False)
2870
+ 2[1[., .], 3[., 4[., .]]]
2871
+ sage: Permutation([4,1,3,2]).binary_search_tree(False)
2872
+ 2[1[., .], 3[., 4[., .]]]
2873
+
2874
+ TESTS::
2875
+
2876
+ sage: Permutation([]).binary_search_tree()
2877
+ .
2878
+ """
2879
+ from sage.combinat.binary_tree import LabelledBinaryTree as LBT
2880
+ res = LBT(None)
2881
+ if left_to_right:
2882
+ gen = self
2883
+ else:
2884
+ gen = self[::-1]
2885
+ for i in gen:
2886
+ res = res.binary_search_insert(i)
2887
+ return res
2888
+
2889
+
2890
@combinatorial_map(name='Robinson-Schensted tableau shape')
2891
def RS_partition(self):
2892
"""
2893
diff --git a/sage/misc/all.py b/sage/misc/all.py
2894
--- a/sage/misc/all.py
2895
+++ b/sage/misc/all.py
2896
@@ -160,8 +160,6 @@ from lazy_import import lazy_import
2897
2898
from abstract_method import abstract_method
2899
2900
-from binary_tree import BinaryTree
2901
-
2902
from randstate import seed, set_random_seed, initial_seed, current_randstate
2903
2904
from prandom import *
2905
diff --git a/sage/misc/binary_tree.pyx b/sage/misc/binary_tree.pyx
2906
--- a/sage/misc/binary_tree.pyx
2907
+++ b/sage/misc/binary_tree.pyx
2908
@@ -197,6 +197,7 @@ cdef class BinaryTree:
2909
2910
EXAMPLES::
2911
2912
+ sage: from sage.misc.binary_tree import BinaryTree
2913
sage: t = BinaryTree()
2914
sage: t.insert(1)
2915
sage: t.insert(0)
2916
@@ -220,6 +221,7 @@ cdef class BinaryTree:
2917
2918
EXAMPLES::
2919
2920
+ sage: from sage.misc.binary_tree import BinaryTree
2921
sage: t = BinaryTree()
2922
sage: t.insert(3,3)
2923
sage: t.insert(1,1)
2924
@@ -261,6 +263,7 @@ cdef class BinaryTree:
2925
2926
EXAMPLES::
2927
2928
+ sage: from sage.misc.binary_tree import BinaryTree
2929
sage: t = BinaryTree()
2930
sage: t.insert(0,Matrix([[0,0],[1,1]]))
2931
sage: t.insert(0,1)
2932
@@ -279,6 +282,7 @@ cdef class BinaryTree:
2933
2934
EXAMPLES::
2935
2936
+ sage: from sage.misc.binary_tree import BinaryTree
2937
sage: t = BinaryTree()
2938
sage: t.contains(1)
2939
False
2940
@@ -322,6 +326,7 @@ cdef class BinaryTree:
2941
2942
EXAMPLES::
2943
2944
+ sage: from sage.misc.binary_tree import BinaryTree
2945
sage: t = BinaryTree()
2946
sage: t.insert(4,'e')
2947
sage: t.insert(2,'c')
2948
@@ -361,6 +366,7 @@ cdef class BinaryTree:
2949
2950
EXAMPLES::
2951
2952
+ sage: from sage.misc.binary_tree import BinaryTree
2953
sage: t = BinaryTree()
2954
sage: t.insert(4,'e')
2955
sage: t.insert(2,'c')
2956
@@ -399,6 +405,7 @@ cdef class BinaryTree:
2957
2958
EXAMPLES::
2959
2960
+ sage: from sage.misc.binary_tree import BinaryTree
2961
sage: t = BinaryTree()
2962
sage: t.is_empty()
2963
True
2964
diff --git a/sage/structure/list_clone.pyx b/sage/structure/list_clone.pyx
2965
--- a/sage/structure/list_clone.pyx
2966
+++ b/sage/structure/list_clone.pyx
2967
@@ -146,10 +146,9 @@ cdef class ClonableElement(Element):
2968
"""
2969
Abstract class for elements with clone protocol
2970
2971
- This class is a subclasse of
2972
- :class:`Element<sage.structure.element.Element>` and implements the
2973
- "prototype" design pattern (see [Pro]_, [GOF]_). The role of this class
2974
- is:
2975
+ This class is a subclass of :class:`Element<sage.structure.element.Element>`
2976
+ and implements the "prototype" design pattern (see [Pro]_, [GOF]_). The role
2977
+ of this class is:
2978
2979
- to manage copy and mutability and hashing of elements
2980
- to ensure that at the end of a piece of code an object is restored in a
2981
2982