passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,2723 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Abstract recursive trees
4
+
5
+ The purpose of this class is to help implement trees with a specific structure
6
+ on the children of each node. For instance, one could want to define a tree in
7
+ which each node sees its children as linearly (see the :mod:`Ordered Trees
8
+ <sage.combinat.ordered_tree>` module) or cyclically ordered.
9
+
10
+ **Tree structures**
11
+
12
+ Conceptually, one can define a tree structure from any object that can contain
13
+ others. Indeed, a list can contain lists which contain lists which contain
14
+ lists, and thus define a tree ... The same can be done with sets, or any kind
15
+ of iterable objects.
16
+
17
+ While any iterable is sufficient to encode trees, it can prove useful to have
18
+ other methods available like isomorphism tests (see next section), conversions
19
+ to DiGraphs objects (see :meth:`~.AbstractLabelledTree.as_digraph`) or
20
+ computation of the number of automorphisms constrained by the structure on
21
+ children. Providing such methods is the whole purpose of the
22
+ :class:`AbstractTree` class.
23
+
24
+ As a result, the :class:`AbstractTree` class is not meant to be
25
+ instantiated, but extended. It is expected that classes extending this one may
26
+ also inherit from classes representing iterables, for instance
27
+ :class:`~sage.structure.list_clone.ClonableArray` or :class:`~sage.structure.list_clone.ClonableList`
28
+
29
+ **Constrained Trees**
30
+
31
+ The tree built from a specific container will reflect the properties of the
32
+ container. Indeed, if ``A`` is an iterable class whose elements are linearly
33
+ ordered, a class ``B`` extending both of :class:`AbstractTree` and ``A`` will
34
+ be such that the children of a node will be linearly ordered. If ``A`` behaves
35
+ like a set (i.e. if there is no order on the elements it contains), then two
36
+ trees will be considered as equal if one can be obtained from the other
37
+ through permutations between the children of a same node (see next section).
38
+
39
+ **Paths and ID**
40
+
41
+ It is expected that each element of a set of children should be identified by
42
+ its index in the container. This way, any node of the tree can be identified
43
+ by a word describing a path from the root node.
44
+
45
+ **Canonical labellings**
46
+
47
+ Equality between instances of classes extending both :class:`AbstractTree`
48
+ and ``A`` is entirely defined by the equality defined on the elements of
49
+ ``A``. A canonical labelling of such a tree, however, should be such that
50
+ two trees ``a`` and ``b`` satisfying ``a == b`` have the same canonical
51
+ labellings. On the other hand, the canonical labellings of trees ``a`` and
52
+ ``b`` satisfying ``a != b`` are expected to be different.
53
+
54
+ For this reason, the values returned by the :meth:`canonical_labelling
55
+ <AbstractTree.canonical_labelling>` method heavily
56
+ depend on the data structure used for a node's children and **should be**
57
+ **overridden** by most of the classes extending :class:`AbstractTree` if it is
58
+ incoherent with the data structure.
59
+
60
+ **Authors**
61
+
62
+ - Florent Hivert (2010-2011): initial revision
63
+ - Frédéric Chapoton (2011): contributed some methods
64
+ """
65
+ import itertools
66
+
67
+ from sage.structure.list_clone import ClonableArray
68
+ from sage.rings.integer import Integer
69
+ from sage.misc.misc_c import prod
70
+
71
+ # Unfortunately Cython forbids multiple inheritance. Therefore, we do not
72
+ # inherit from SageObject to be able to inherit from Element or a subclass
73
+ # of it later.
74
+
75
+
76
+ class AbstractTree:
77
+ """
78
+ Abstract Tree.
79
+
80
+ There is no data structure defined here, as this class is meant to be
81
+ extended, not instantiated.
82
+
83
+ .. rubric:: How should this class be extended?
84
+
85
+ A class extending :class:`AbstractTree
86
+ <sage.combinat.abstract_tree.AbstractTree>` should respect several
87
+ assumptions:
88
+
89
+ * For a tree ``T``, the call ``iter(T)`` should return an iterator on the
90
+ children of the root ``T``.
91
+
92
+ * The :meth:`canonical_labelling
93
+ <AbstractTree.canonical_labelling>` method
94
+ should return the same value for trees that are considered equal (see the
95
+ "canonical labellings" section in the documentation of the
96
+ :class:`AbstractTree <sage.combinat.abstract_tree.AbstractTree>` class).
97
+
98
+ * For a tree ``T`` the call ``T.parent().labelled_trees()`` should return
99
+ a parent for labelled trees of the same kind: for example,
100
+
101
+ - if ``T`` is a binary tree, ``T.parent()`` is ``BinaryTrees()`` and
102
+ ``T.parent().labelled_trees()`` is ``LabelledBinaryTrees()``
103
+
104
+ - if ``T`` is an ordered tree, ``T.parent()`` is ``OrderedTrees()`` and
105
+ ``T.parent().labelled_trees()`` is ``LabelledOrderedTrees()``
106
+
107
+ TESTS::
108
+
109
+ sage: TestSuite(OrderedTree()).run()
110
+ sage: TestSuite(BinaryTree()).run()
111
+ """
112
+
113
+ def pre_order_traversal_iter(self):
114
+ r"""
115
+ The depth-first pre-order traversal iterator.
116
+
117
+ This method iters each node following the depth-first pre-order
118
+ traversal algorithm (recursive implementation). The algorithm
119
+ is::
120
+
121
+ yield the root (in the case of binary trees, if it is not
122
+ a leaf);
123
+ then explore each subtree (by the algorithm) from the
124
+ leftmost one to the rightmost one.
125
+
126
+ EXAMPLES:
127
+
128
+ For example, on the following binary tree `b`::
129
+
130
+ | ___3____ |
131
+ | / \ |
132
+ | 1 _7_ |
133
+ | \ / \ |
134
+ | 2 5 8 |
135
+ | / \ |
136
+ | 4 6 |
137
+
138
+ (only the nodes shown), the depth-first pre-order traversal
139
+ algorithm explores `b` in the following order of nodes:
140
+ `3,1,2,7,5,4,6,8`.
141
+
142
+ Another example::
143
+
144
+ | __1____ |
145
+ | / / / |
146
+ | 2 6 8_ |
147
+ | | | / / |
148
+ | 3_ 7 9 10 |
149
+ | / / |
150
+ | 4 5 |
151
+
152
+ The algorithm explores this labelled tree in the following
153
+ order: `1,2,3,4,5,6,7,8,9,10`.
154
+
155
+ TESTS::
156
+
157
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
158
+ sage: ascii_art([b])
159
+ [ ___3____ ]
160
+ [ / \ ]
161
+ [ 1 _7_ ]
162
+ [ \ / \ ]
163
+ [ 2 5 8 ]
164
+ [ / \ ]
165
+ [ 4 6 ]
166
+ sage: [n.label() for n in b.pre_order_traversal_iter()]
167
+ [3, 1, 2, 7, 5, 4, 6, 8]
168
+
169
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
170
+ sage: ascii_art([t])
171
+ [ __1____ ]
172
+ [ / / / ]
173
+ [ 2 6 8_ ]
174
+ [ | | / / ]
175
+ [ 3_ 7 9 10 ]
176
+ [ / / ]
177
+ [ 4 5 ]
178
+ sage: [n.label() for n in t.pre_order_traversal_iter()]
179
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
180
+
181
+ sage: [n for n in BinaryTree(None).pre_order_traversal_iter()]
182
+ []
183
+
184
+ The following test checks that things do not go wrong if some among
185
+ the descendants of the tree are equal or even identical::
186
+
187
+ sage: u = BinaryTree(None)
188
+ sage: v = BinaryTree([u, u])
189
+ sage: w = BinaryTree([v, v])
190
+ sage: t = BinaryTree([w, w])
191
+ sage: t.node_number()
192
+ 7
193
+ sage: l = [1 for i in t.pre_order_traversal_iter()]
194
+ sage: len(l)
195
+ 7
196
+ """
197
+ if self.is_empty():
198
+ return
199
+ yield self
200
+ yield from itertools.chain(*[c.pre_order_traversal_iter()
201
+ for c in self])
202
+
203
+ def iterative_pre_order_traversal(self, action=None):
204
+ r"""
205
+ Run the depth-first pre-order traversal algorithm (iterative
206
+ implementation) and subject every node encountered
207
+ to some procedure ``action``. The algorithm is::
208
+
209
+ manipulate the root with function `action` (in the case
210
+ of a binary tree, only if the root is not a leaf);
211
+ then explore each subtree (by the algorithm) from the
212
+ leftmost one to the rightmost one.
213
+
214
+ INPUT:
215
+
216
+ - ``action`` -- (optional) a function which takes a node as
217
+ input, and does something during the exploration
218
+
219
+ OUTPUT:
220
+
221
+ ``None``. (This is *not* an iterator.)
222
+
223
+ .. SEEALSO::
224
+
225
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal_iter()`
226
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal()`
227
+
228
+ TESTS::
229
+
230
+ sage: l = []
231
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
232
+ sage: b
233
+ 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
234
+ sage: b.iterative_pre_order_traversal(lambda node: l.append(node.label()))
235
+ sage: l
236
+ [3, 1, 2, 7, 5, 4, 6, 8]
237
+
238
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
239
+ sage: t
240
+ 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
241
+ sage: l = []
242
+ sage: t.iterative_pre_order_traversal(lambda node: l.append(node.label()))
243
+ sage: l
244
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
245
+ sage: l = []
246
+
247
+ sage: BinaryTree().canonical_labelling().\
248
+ ....: pre_order_traversal(lambda node: l.append(node.label()))
249
+ sage: l
250
+ []
251
+ sage: OrderedTree([]).canonical_labelling().\
252
+ ....: iterative_pre_order_traversal(lambda node: l.append(node.label()))
253
+ sage: l
254
+ [1]
255
+
256
+ The following test checks that things do not go wrong if some among
257
+ the descendants of the tree are equal or even identical::
258
+
259
+ sage: u = BinaryTree(None)
260
+ sage: v = BinaryTree([u, u])
261
+ sage: w = BinaryTree([v, v])
262
+ sage: t = BinaryTree([w, w])
263
+ sage: t.node_number()
264
+ 7
265
+ sage: l = []
266
+ sage: t.iterative_pre_order_traversal(lambda node: l.append(1))
267
+ sage: len(l)
268
+ 7
269
+ """
270
+ if self.is_empty():
271
+ return
272
+ if action is None:
273
+ def action(x):
274
+ return None
275
+ stack = []
276
+ stack.append(self)
277
+ while stack:
278
+ node = stack.pop()
279
+ action(node)
280
+ for subtree in reversed(node):
281
+ if not subtree.is_empty():
282
+ stack.append(subtree)
283
+
284
+ def pre_order_traversal(self, action=None):
285
+ r"""
286
+ Run the depth-first pre-order traversal algorithm (recursive
287
+ implementation) and subject every node encountered
288
+ to some procedure ``action``. The algorithm is::
289
+
290
+ manipulate the root with function `action` (in the case
291
+ of a binary tree, only if the root is not a leaf);
292
+ then explore each subtree (by the algorithm) from the
293
+ leftmost one to the rightmost one.
294
+
295
+ INPUT:
296
+
297
+ - ``action`` -- (optional) a function which takes a node as
298
+ input, and does something during the exploration
299
+
300
+ OUTPUT:
301
+
302
+ ``None``. (This is *not* an iterator.)
303
+
304
+ EXAMPLES:
305
+
306
+ For example, on the following binary tree `b`::
307
+
308
+ | ___3____ |
309
+ | / \ |
310
+ | 1 _7_ |
311
+ | \ / \ |
312
+ | 2 5 8 |
313
+ | / \ |
314
+ | 4 6 |
315
+
316
+ the depth-first pre-order traversal algorithm explores `b` in the
317
+ following order of nodes: `3,1,2,7,5,4,6,8`.
318
+
319
+ Another example::
320
+
321
+ | __1____ |
322
+ | / / / |
323
+ | 2 6 8_ |
324
+ | | | / / |
325
+ | 3_ 7 9 10 |
326
+ | / / |
327
+ | 4 5 |
328
+
329
+ The algorithm explores this tree in the following order:
330
+ `1,2,3,4,5,6,7,8,9,10`.
331
+
332
+ .. SEEALSO::
333
+
334
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.pre_order_traversal_iter()`
335
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.iterative_pre_order_traversal()`
336
+
337
+ TESTS::
338
+
339
+ sage: l = []
340
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
341
+ sage: b
342
+ 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
343
+ sage: b.pre_order_traversal(lambda node: l.append(node.label()))
344
+ sage: l
345
+ [3, 1, 2, 7, 5, 4, 6, 8]
346
+ sage: li = []
347
+ sage: b.iterative_pre_order_traversal(lambda node: li.append(node.label()))
348
+ sage: l == li
349
+ True
350
+
351
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
352
+ sage: t
353
+ 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
354
+ sage: l = []
355
+ sage: t.pre_order_traversal(lambda node: l.append(node.label()))
356
+ sage: l
357
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
358
+ sage: li = []
359
+ sage: t.iterative_pre_order_traversal(lambda node: li.append(node.label()))
360
+ sage: l == li
361
+ True
362
+
363
+ sage: l = []
364
+ sage: BinaryTree().canonical_labelling().\
365
+ ....: pre_order_traversal(lambda node: l.append(node.label()))
366
+ sage: l
367
+ []
368
+ sage: OrderedTree([]).canonical_labelling().\
369
+ ....: pre_order_traversal(lambda node: l.append(node.label()))
370
+ sage: l
371
+ [1]
372
+
373
+ The following test checks that things do not go wrong if some among
374
+ the descendants of the tree are equal or even identical::
375
+
376
+ sage: u = BinaryTree(None)
377
+ sage: v = BinaryTree([u, u])
378
+ sage: w = BinaryTree([v, v])
379
+ sage: t = BinaryTree([w, w])
380
+ sage: t.node_number()
381
+ 7
382
+ sage: l = []
383
+ sage: t.pre_order_traversal(lambda node: l.append(1))
384
+ sage: len(l)
385
+ 7
386
+ """
387
+ if action is None:
388
+ def action(x):
389
+ return None
390
+ for node in self.pre_order_traversal_iter():
391
+ action(node)
392
+
393
+ def post_order_traversal_iter(self):
394
+ r"""
395
+ The depth-first post-order traversal iterator.
396
+
397
+ This method iters each node following the depth-first post-order
398
+ traversal algorithm (recursive implementation). The algorithm
399
+ is::
400
+
401
+ explore each subtree (by the algorithm) from the
402
+ leftmost one to the rightmost one;
403
+ then yield the root (in the case of binary trees, only if
404
+ it is not a leaf).
405
+
406
+ EXAMPLES:
407
+
408
+ For example on the following binary tree `b`::
409
+
410
+ | ___3____ |
411
+ | / \ |
412
+ | 1 _7_ |
413
+ | \ / \ |
414
+ | 2 5 8 |
415
+ | / \ |
416
+ | 4 6 |
417
+
418
+ (only the nodes are shown), the depth-first post-order traversal
419
+ algorithm explores `b` in the following order of nodes:
420
+ `2,1,4,6,5,8,7,3`.
421
+
422
+ For another example, consider the labelled tree::
423
+
424
+ | __1____ |
425
+ | / / / |
426
+ | 2 6 8_ |
427
+ | | | / / |
428
+ | 3_ 7 9 10 |
429
+ | / / |
430
+ | 4 5 |
431
+
432
+ The algorithm explores this tree in the following order:
433
+ `4,5,3,2,7,6,9,10,8,1`.
434
+
435
+ TESTS::
436
+
437
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
438
+ sage: ascii_art([b])
439
+ [ ___3____ ]
440
+ [ / \ ]
441
+ [ 1 _7_ ]
442
+ [ \ / \ ]
443
+ [ 2 5 8 ]
444
+ [ / \ ]
445
+ [ 4 6 ]
446
+ sage: [node.label() for node in b.post_order_traversal_iter()]
447
+ [2, 1, 4, 6, 5, 8, 7, 3]
448
+
449
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
450
+ sage: ascii_art([t])
451
+ [ __1____ ]
452
+ [ / / / ]
453
+ [ 2 6 8_ ]
454
+ [ | | / / ]
455
+ [ 3_ 7 9 10 ]
456
+ [ / / ]
457
+ [ 4 5 ]
458
+ sage: [node.label() for node in t.post_order_traversal_iter()]
459
+ [4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
460
+
461
+ sage: [node.label() for node in BinaryTree().canonical_labelling().\
462
+ ....: post_order_traversal_iter()]
463
+ []
464
+ sage: [node.label() for node in OrderedTree([]).\
465
+ ....: canonical_labelling().post_order_traversal_iter()]
466
+ [1]
467
+
468
+ The following test checks that things do not go wrong if some among
469
+ the descendants of the tree are equal or even identical::
470
+
471
+ sage: u = BinaryTree(None)
472
+ sage: v = BinaryTree([u, u])
473
+ sage: w = BinaryTree([v, v])
474
+ sage: t = BinaryTree([w, w])
475
+ sage: t.node_number()
476
+ 7
477
+ sage: l = [1 for i in t.post_order_traversal_iter()]
478
+ sage: len(l)
479
+ 7
480
+ """
481
+ if self.is_empty():
482
+ return
483
+ yield from itertools.chain(*[c.post_order_traversal_iter()
484
+ for c in self])
485
+ yield self
486
+
487
+ def post_order_traversal(self, action=None):
488
+ r"""
489
+ Run the depth-first post-order traversal algorithm (recursive
490
+ implementation) and subject every node encountered
491
+ to some procedure ``action``. The algorithm is::
492
+
493
+ explore each subtree (by the algorithm) from the
494
+ leftmost one to the rightmost one;
495
+ then manipulate the root with function `action` (in the
496
+ case of a binary tree, only if the root is not a leaf).
497
+
498
+ INPUT:
499
+
500
+ - ``action`` -- (optional) a function which takes a node as
501
+ input, and does something during the exploration
502
+
503
+ OUTPUT:
504
+
505
+ ``None``. (This is *not* an iterator.)
506
+
507
+ .. SEEALSO::
508
+
509
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.post_order_traversal_iter()`
510
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.iterative_post_order_traversal()`
511
+
512
+ TESTS::
513
+
514
+ sage: l = []
515
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
516
+ sage: b
517
+ 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
518
+ sage: b.post_order_traversal(lambda node: l.append(node.label()))
519
+ sage: l
520
+ [2, 1, 4, 6, 5, 8, 7, 3]
521
+
522
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).\
523
+ ....: canonical_labelling(); t
524
+ 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
525
+ sage: l = []
526
+ sage: t.post_order_traversal(lambda node: l.append(node.label()))
527
+ sage: l
528
+ [4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
529
+
530
+ sage: l = []
531
+ sage: BinaryTree().canonical_labelling().\
532
+ ....: post_order_traversal(lambda node: l.append(node.label()))
533
+ sage: l
534
+ []
535
+ sage: OrderedTree([]).canonical_labelling().\
536
+ ....: post_order_traversal(lambda node: l.append(node.label()))
537
+ sage: l
538
+ [1]
539
+
540
+ The following test checks that things do not go wrong if some among
541
+ the descendants of the tree are equal or even identical::
542
+
543
+ sage: u = BinaryTree(None)
544
+ sage: v = BinaryTree([u, u])
545
+ sage: w = BinaryTree([v, v])
546
+ sage: t = BinaryTree([w, w])
547
+ sage: t.node_number()
548
+ 7
549
+ sage: l = []
550
+ sage: t.post_order_traversal(lambda node: l.append(1))
551
+ sage: len(l)
552
+ 7
553
+ """
554
+ if action is None:
555
+ def action(x):
556
+ return None
557
+ for node in self.post_order_traversal_iter():
558
+ action(node)
559
+
560
+ def iterative_post_order_traversal(self, action=None):
561
+ r"""
562
+ Run the depth-first post-order traversal algorithm (iterative
563
+ implementation) and subject every node encountered
564
+ to some procedure ``action``. The algorithm is::
565
+
566
+ explore each subtree (by the algorithm) from the
567
+ leftmost one to the rightmost one;
568
+ then manipulate the root with function `action` (in the
569
+ case of a binary tree, only if the root is not a leaf).
570
+
571
+ INPUT:
572
+
573
+ - ``action`` -- (optional) a function which takes a node as
574
+ input, and does something during the exploration
575
+
576
+ OUTPUT:
577
+
578
+ ``None``. (This is *not* an iterator.)
579
+
580
+ .. SEEALSO::
581
+
582
+ - :meth:`~sage.combinat.abstract_tree.AbstractTree.post_order_traversal_iter()`
583
+
584
+ TESTS::
585
+
586
+ sage: l = []
587
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
588
+ sage: b
589
+ 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
590
+ sage: b.iterative_post_order_traversal(lambda node: l.append(node.label()))
591
+ sage: l
592
+ [2, 1, 4, 6, 5, 8, 7, 3]
593
+
594
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
595
+ sage: t
596
+ 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
597
+ sage: l = []
598
+ sage: t.iterative_post_order_traversal(lambda node: l.append(node.label()))
599
+ sage: l
600
+ [4, 5, 3, 2, 7, 6, 9, 10, 8, 1]
601
+
602
+ sage: l = []
603
+ sage: BinaryTree().canonical_labelling().\
604
+ ....: iterative_post_order_traversal(
605
+ ....: lambda node: l.append(node.label()))
606
+ sage: l
607
+ []
608
+ sage: OrderedTree([]).canonical_labelling().\
609
+ ....: iterative_post_order_traversal(
610
+ ....: lambda node: l.append(node.label()))
611
+ sage: l
612
+ [1]
613
+
614
+ The following test checks that things do not go wrong if some among
615
+ the descendants of the tree are equal or even identical::
616
+
617
+ sage: u = BinaryTree(None)
618
+ sage: v = BinaryTree([u, u])
619
+ sage: w = BinaryTree([v, v])
620
+ sage: t = BinaryTree([w, w])
621
+ sage: t.node_number()
622
+ 7
623
+ sage: l = []
624
+ sage: t.iterative_post_order_traversal(lambda node: l.append(1))
625
+ sage: len(l)
626
+ 7
627
+ """
628
+ if self.is_empty():
629
+ return
630
+ if action is None:
631
+ def action(x):
632
+ return None
633
+ stack = [self]
634
+ while stack:
635
+ node = stack[-1]
636
+ if node is not None:
637
+ # A "None" on the stack means that the node right before
638
+ # it on the stack has already been "exploded" into
639
+ # subtrees, and should not be exploded again, but instead
640
+ # should be manipulated and removed from the stack.
641
+ stack.append(None)
642
+ for subtree in reversed(node):
643
+ if not subtree.is_empty():
644
+ stack.append(subtree)
645
+ else:
646
+ stack.pop()
647
+ node = stack.pop()
648
+ action(node)
649
+
650
+ def contour_traversal(self, first_action=None, middle_action=None, final_action=None, leaf_action=None):
651
+ r"""
652
+ Run the counterclockwise contour traversal algorithm (iterative
653
+ implementation) and subject every node encountered
654
+ to some procedure ``first_action``, ``middle_action`` or ``final_action`` each time it reaches it.
655
+
656
+ ALGORITHM:
657
+
658
+ - if the root is a leaf, apply `leaf_action`
659
+ - else
660
+ - apply `first_action` to the root
661
+ - iteratively apply `middle_action` to the root and traverse each subtree
662
+ from the leftmost one to the rightmost one
663
+ - apply `final_action` to the root
664
+
665
+ INPUT:
666
+
667
+ - ``first_action`` -- (optional) a function which takes a node as
668
+ input, and does something the first time it is reached during exploration
669
+
670
+ - ``middle_action`` -- (optional) a function which takes a node as
671
+ input, and does something each time it explore one of its children
672
+
673
+ - ``final_action`` -- (optional) a function which takes a node as
674
+ input, and does something the last time it is reached during exploration
675
+
676
+ - ``leaf_action`` -- (optional) a function which takes a leaf as
677
+ input, and does something when it is reached during exploration.
678
+
679
+ OUTPUT:
680
+
681
+ ``None``. (This is *not* an iterator.)
682
+
683
+ TESTS::
684
+
685
+ sage: l = []
686
+ sage: t = OrderedTree([[],[[],[],]]).canonical_labelling()
687
+ sage: t
688
+ 1[2[], 3[4[], 5[]]]
689
+ sage: t.contour_traversal(lambda node: (l.append(node.label()),l.append('a')),
690
+ ....: lambda node: (l.append(node.label()),l.append('b')),
691
+ ....: lambda node: (l.append(node.label()),l.append('c')),
692
+ ....: lambda node: (l.append(node.label())))
693
+ sage: l
694
+ [1, 'a', 1, 'b', 2, 1, 'b', 3, 'a', 3, 'b', 4, 3, 'b', 5, 3, 'c', 1, 'c']
695
+
696
+ sage: l = []
697
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
698
+ sage: b
699
+ 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]]
700
+ sage: b.contour_traversal(lambda node: l.append(node.label()),
701
+ ....: lambda node: l.append(node.label()),
702
+ ....: lambda node: l.append(node.label()),
703
+ ....: None)
704
+ sage: l
705
+ [3, 3, 1, 1, 1, 2, 2, 2, 2, 1, 3, 7, 7, 5, 5, 4, 4, 4, 4, 5, 6, 6, 6, 6, 5, 7, 8, 8, 8, 8, 7, 3]
706
+
707
+ The following test checks that things do not go wrong if some among
708
+ the descendants of the tree are equal or even identical::
709
+
710
+ sage: u = BinaryTree(None)
711
+ sage: v = BinaryTree([u, u])
712
+ sage: w = BinaryTree([v, v])
713
+ sage: t = BinaryTree([w, w])
714
+ sage: t.node_number()
715
+ 7
716
+ sage: l = []
717
+ sage: t.contour_traversal(first_action = lambda node: l.append(0))
718
+ sage: len(l)
719
+ 7
720
+ """
721
+ if first_action is None:
722
+ def first_action(x):
723
+ return
724
+ if middle_action is None:
725
+ def middle_action(x):
726
+ return
727
+ if final_action is None:
728
+ def final_action(x):
729
+ return
730
+ if leaf_action is None:
731
+ def leaf_action(x):
732
+ return
733
+ stack = []
734
+ stack.append(self)
735
+ corners = [0, 0]
736
+ while stack:
737
+ node = stack.pop()
738
+ if not node:
739
+ leaf_action(node)
740
+ corners.pop()
741
+ corners[-1] += 1
742
+ elif not corners[-1]:
743
+ first_action(node)
744
+ middle_action(node)
745
+ stack.append(node)
746
+ stack.append(node[0])
747
+ corners.append(0)
748
+ elif corners[-1] == len(node):
749
+ final_action(node)
750
+ corners.pop()
751
+ corners[-1] += 1
752
+ else:
753
+ middle_action(node)
754
+ stack.append(node)
755
+ stack.append(node[corners[-1]])
756
+ corners.append(0)
757
+
758
+ def breadth_first_order_traversal(self, action=None):
759
+ r"""
760
+ Run the breadth-first post-order traversal algorithm
761
+ and subject every node encountered to some procedure
762
+ ``action``. The algorithm is::
763
+
764
+ queue <- [ root ];
765
+ while the queue is not empty:
766
+ node <- pop( queue );
767
+ manipulate the node;
768
+ prepend to the queue the list of all subtrees of
769
+ the node (from the rightmost to the leftmost).
770
+
771
+ INPUT:
772
+
773
+ - ``action`` -- (optional) a function which takes a node as
774
+ input, and does something during the exploration
775
+
776
+ OUTPUT:
777
+
778
+ ``None``. (This is *not* an iterator.)
779
+
780
+ EXAMPLES:
781
+
782
+ For example, on the following binary tree `b`::
783
+
784
+ | ___3____ |
785
+ | / \ |
786
+ | 1 _7_ |
787
+ | \ / \ |
788
+ | 2 5 8 |
789
+ | / \ |
790
+ | 4 6 |
791
+
792
+ the breadth-first order traversal algorithm explores `b` in the
793
+ following order of nodes: `3,1,7,2,5,8,4,6`.
794
+
795
+ TESTS::
796
+
797
+ sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling()
798
+ sage: l = []
799
+ sage: b.breadth_first_order_traversal(lambda node: l.append(node.label()))
800
+ sage: l
801
+ [3, 1, 7, 2, 5, 8, 4, 6]
802
+
803
+ sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling()
804
+ sage: t
805
+ 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]]
806
+ sage: l = []
807
+ sage: t.breadth_first_order_traversal(lambda node: l.append(node.label()))
808
+ sage: l
809
+ [1, 2, 6, 8, 3, 7, 9, 10, 4, 5]
810
+
811
+ sage: l = []
812
+ sage: BinaryTree().canonical_labelling().\
813
+ ....: breadth_first_order_traversal(
814
+ ....: lambda node: l.append(node.label()))
815
+ sage: l
816
+ []
817
+ sage: OrderedTree([]).canonical_labelling().\
818
+ ....: breadth_first_order_traversal(
819
+ ....: lambda node: l.append(node.label()))
820
+ sage: l
821
+ [1]
822
+ """
823
+ if self.is_empty():
824
+ return
825
+ if action is None:
826
+ def action(x):
827
+ return None
828
+ queue = []
829
+ queue.append(self)
830
+ while queue:
831
+ node = queue.pop()
832
+ action(node)
833
+ for subtree in node:
834
+ if not subtree.is_empty():
835
+ queue.insert(0, subtree)
836
+
837
+ def paths_at_depth(self, depth, path=[]):
838
+ r"""
839
+ Return a generator for all paths at a fixed depth.
840
+
841
+ This iterates over all paths for nodes that are at the given depth.
842
+
843
+ Here the root is considered to have depth 0.
844
+
845
+ INPUT:
846
+
847
+ - ``depth`` -- integer
848
+ - ``path`` -- (optional) list; given path used in the recursion
849
+
850
+ .. WARNING::
851
+
852
+ The ``path`` option should not be used directly.
853
+
854
+ .. SEEALSO::
855
+
856
+ :meth:`paths`, :meth:`paths_to_the_right`, :meth:`node_number_at_depth`
857
+
858
+ EXAMPLES::
859
+
860
+ sage: T = OrderedTree([[[], [[], [[]]]], [], [[[],[]]], [], []])
861
+ sage: ascii_art(T)
862
+ ______o_______
863
+ / / / / /
864
+ _o__ o o o o
865
+ / / |
866
+ o o_ o_
867
+ / / / /
868
+ o o o o
869
+ |
870
+ o
871
+ sage: list(T.paths_at_depth(0))
872
+ [()]
873
+ sage: list(T.paths_at_depth(2))
874
+ [(0, 0), (0, 1), (2, 0)]
875
+ sage: list(T.paths_at_depth(4))
876
+ [(0, 1, 1, 0)]
877
+ sage: list(T.paths_at_depth(5))
878
+ []
879
+
880
+ sage: T2 = OrderedTree([])
881
+ sage: list(T2.paths_at_depth(0))
882
+ [()]
883
+ """
884
+ if not depth:
885
+ yield tuple(path)
886
+ else:
887
+ for i in range(len(self)):
888
+ yield from self[i].paths_at_depth(depth - 1, path + [i])
889
+
890
+ def node_number_at_depth(self, depth):
891
+ r"""
892
+ Return the number of nodes at a given depth.
893
+
894
+ This counts all nodes that are at the given depth.
895
+
896
+ Here the root is considered to have depth 0.
897
+
898
+ INPUT:
899
+
900
+ - ``depth`` -- integer
901
+
902
+ .. SEEALSO::
903
+
904
+ :meth:`node_number`, :meth:`node_number_to_the_right`, :meth:`paths_at_depth`
905
+
906
+ EXAMPLES::
907
+
908
+ sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []])
909
+ sage: ascii_art(T)
910
+ ___o____
911
+ / / /
912
+ o_ o_ o
913
+ / / / /
914
+ o o o o
915
+ | |
916
+ o o
917
+ |
918
+ o
919
+ sage: [T.node_number_at_depth(i) for i in range(6)]
920
+ [1, 3, 4, 2, 1, 0]
921
+
922
+ TESTS:
923
+
924
+ Check that the empty tree has no nodes (:issue:`29134`)::
925
+
926
+ sage: T = BinaryTree()
927
+ sage: T
928
+ .
929
+ sage: T.is_empty()
930
+ True
931
+ sage: [T.node_number_at_depth(i) for i in range(3)]
932
+ [0, 0, 0]
933
+
934
+ Check that we do not hit a recursion limit::
935
+
936
+ sage: T = OrderedTree([])
937
+ sage: for _ in range(9999):
938
+ ....: T = OrderedTree([T])
939
+ sage: T.node_number_at_depth(2000)
940
+ 1
941
+ """
942
+ if self.is_empty():
943
+ return 0
944
+ m = 0
945
+
946
+ def fr_action(node):
947
+ nonlocal m, depths, depth
948
+ if depths[-1] == depth:
949
+ m += 1
950
+
951
+ def m_action(node):
952
+ nonlocal depths
953
+ depths.append(depths[-1] + 1)
954
+
955
+ def fn_action(node):
956
+ nonlocal depths
957
+ depths.pop()
958
+
959
+ def lf_action(node):
960
+ nonlocal m, depths, depth
961
+ if depths[-1] == depth:
962
+ m += 1
963
+ depths.pop()
964
+
965
+ depths = [0]
966
+ self.contour_traversal(fr_action, m_action, fn_action, lf_action)
967
+ return Integer(m)
968
+
969
+ def paths_to_the_right(self, path):
970
+ r"""
971
+ Return a generator of paths for all nodes at the same
972
+ depth and to the right of the node identified by ``path``.
973
+
974
+ This iterates over the paths for nodes that are at the same
975
+ depth as the given one, and strictly to its right.
976
+
977
+ INPUT:
978
+
979
+ - ``path`` -- any path in the tree
980
+
981
+ .. SEEALSO::
982
+
983
+ :meth:`paths`, :meth:`paths_at_depth`, :meth:`node_number_to_the_right`
984
+
985
+ EXAMPLES::
986
+
987
+ sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []])
988
+ sage: ascii_art(T)
989
+ ___o____
990
+ / / /
991
+ o_ o_ o
992
+ / / / /
993
+ o o o o
994
+ | |
995
+ o o
996
+ |
997
+ o
998
+ sage: g = T.paths_to_the_right(())
999
+ sage: list(g)
1000
+ []
1001
+
1002
+ sage: g = T.paths_to_the_right((0,))
1003
+ sage: list(g)
1004
+ [(1,), (2,)]
1005
+
1006
+ sage: g = T.paths_to_the_right((0,1))
1007
+ sage: list(g)
1008
+ [(1, 0), (1, 1)]
1009
+
1010
+ sage: g = T.paths_to_the_right((0,1,0))
1011
+ sage: list(g)
1012
+ [(1, 1, 0)]
1013
+
1014
+ sage: g = T.paths_to_the_right((1,2))
1015
+ sage: list(g)
1016
+ []
1017
+ """
1018
+ depth = len(path)
1019
+ if (not depth) or path[0] >= len(self):
1020
+ return
1021
+ for i in range(path[0] + 1, len(self)):
1022
+ for p in self[i].paths_at_depth(depth - 1, path=[i]):
1023
+ yield p
1024
+ for p in self[path[0]].paths_to_the_right(path[1:]):
1025
+ yield tuple([path[0]] + list(p))
1026
+
1027
+ def node_number_to_the_right(self, path):
1028
+ r"""
1029
+ Return the number of nodes at the same depth and to the right of
1030
+ the node identified by ``path``.
1031
+
1032
+ This counts the nodes that are at the same depth as the given
1033
+ one, and strictly to its right.
1034
+
1035
+ .. SEEALSO::
1036
+
1037
+ :meth:`node_number`, :meth:`node_number_at_depth`, :meth:`paths_to_the_right`
1038
+
1039
+ EXAMPLES::
1040
+
1041
+ sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []])
1042
+ sage: ascii_art(T)
1043
+ ___o____
1044
+ / / /
1045
+ o_ o_ o
1046
+ / / / /
1047
+ o o o o
1048
+ | |
1049
+ o o
1050
+ |
1051
+ o
1052
+ sage: T.node_number_to_the_right(())
1053
+ 0
1054
+ sage: T.node_number_to_the_right((0,))
1055
+ 2
1056
+ sage: T.node_number_to_the_right((0,1))
1057
+ 2
1058
+ sage: T.node_number_to_the_right((0,1,0))
1059
+ 1
1060
+
1061
+ sage: T = OrderedTree([])
1062
+ sage: T.node_number_to_the_right(())
1063
+ 0
1064
+ """
1065
+ depth = len(path)
1066
+ if depth == 0:
1067
+ return Integer(0)
1068
+ result = sum(son.node_number_at_depth(depth - 1)
1069
+ for son in self[path[0] + 1:])
1070
+ if path[0] < len(self) and path[0] >= 0:
1071
+ result += self[path[0]].node_number_to_the_right(path[1:])
1072
+ return result
1073
+
1074
+ def subtrees(self):
1075
+ """
1076
+ Return a generator for all nonempty subtrees of ``self``.
1077
+
1078
+ The number of nonempty subtrees of a tree is its number of
1079
+ nodes. (The word "nonempty" makes a difference only in the
1080
+ case of binary trees. For ordered trees, for example, all
1081
+ trees are nonempty.)
1082
+
1083
+ EXAMPLES::
1084
+
1085
+ sage: list(OrderedTree([]).subtrees())
1086
+ [[]]
1087
+ sage: list(OrderedTree([[],[[]]]).subtrees())
1088
+ [[[], [[]]], [], [[]], []]
1089
+
1090
+ sage: list(OrderedTree([[],[[]]]).canonical_labelling().subtrees())
1091
+ [1[2[], 3[4[]]], 2[], 3[4[]], 4[]]
1092
+
1093
+ sage: list(BinaryTree([[],[[],[]]]).subtrees())
1094
+ [[[., .], [[., .], [., .]]], [., .], [[., .], [., .]], [., .], [., .]]
1095
+
1096
+ sage: v = BinaryTree([[],[]])
1097
+ sage: list(v.canonical_labelling().subtrees())
1098
+ [2[1[., .], 3[., .]], 1[., .], 3[., .]]
1099
+
1100
+ TESTS::
1101
+
1102
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
1103
+ sage: t.node_number() == len(list(t.subtrees()))
1104
+ True
1105
+ sage: list(BinaryTree().subtrees())
1106
+ []
1107
+ sage: bt = BinaryTree([[],[[],[]]])
1108
+ sage: bt.node_number() == len(list(bt.subtrees()))
1109
+ True
1110
+ """
1111
+ return self.pre_order_traversal_iter()
1112
+
1113
+ def paths(self):
1114
+ """
1115
+ Return a generator for all paths to nodes of ``self``.
1116
+
1117
+ OUTPUT:
1118
+
1119
+ This method returns a list of sequences of integers. Each of these
1120
+ sequences represents a path from the root node to some node. For
1121
+ instance, `(1, 3, 2, 5, 0, 3)` represents the node obtained by
1122
+ choosing the 1st child of the root node (in the ordering returned
1123
+ by ``iter``), then the 3rd child of its child, then the 2nd child
1124
+ of the latter, etc. (where the labelling of the children is
1125
+ zero-based).
1126
+
1127
+ The root element is represented by the empty tuple ``()``.
1128
+
1129
+ .. SEEALSO::
1130
+
1131
+ :meth:`paths_at_depth`, :meth:`paths_to_the_right`
1132
+
1133
+ EXAMPLES::
1134
+
1135
+ sage: list(OrderedTree([]).paths())
1136
+ [()]
1137
+ sage: list(OrderedTree([[],[[]]]).paths())
1138
+ [(), (0,), (1,), (1, 0)]
1139
+
1140
+ sage: list(BinaryTree([[],[[],[]]]).paths())
1141
+ [(), (0,), (1,), (1, 0), (1, 1)]
1142
+
1143
+ TESTS::
1144
+
1145
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
1146
+ sage: t.node_number() == len(list(t.paths()))
1147
+ True
1148
+ sage: list(BinaryTree().paths())
1149
+ []
1150
+ sage: bt = BinaryTree([[],[[],[]]])
1151
+ sage: bt.node_number() == len(list(bt.paths()))
1152
+ True
1153
+ """
1154
+ if not self.is_empty():
1155
+ yield ()
1156
+ for i, t in enumerate(self):
1157
+ for p in t.paths():
1158
+ yield (i,) + p
1159
+
1160
+ def node_number(self):
1161
+ """
1162
+ Return the number of nodes of ``self``.
1163
+
1164
+ .. SEEALSO::
1165
+
1166
+ :meth:`node_number_at_depth`, :meth:`node_number_to_the_right`
1167
+
1168
+ EXAMPLES::
1169
+
1170
+ sage: OrderedTree().node_number()
1171
+ 1
1172
+ sage: OrderedTree([]).node_number()
1173
+ 1
1174
+ sage: OrderedTree([[],[]]).node_number()
1175
+ 3
1176
+ sage: OrderedTree([[],[[]]]).node_number()
1177
+ 4
1178
+ sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number()
1179
+ 13
1180
+
1181
+ EXAMPLES::
1182
+
1183
+ sage: BinaryTree(None).node_number()
1184
+ 0
1185
+ sage: BinaryTree([]).node_number()
1186
+ 1
1187
+ sage: BinaryTree([[], None]).node_number()
1188
+ 2
1189
+ sage: BinaryTree([[None, [[], []]], None]).node_number()
1190
+ 5
1191
+
1192
+ TESTS:
1193
+
1194
+ Check that we do not hit a recursion limit::
1195
+
1196
+ sage: T = OrderedTree([])
1197
+ sage: for _ in range(9999):
1198
+ ....: T = OrderedTree([T])
1199
+ sage: T.node_number()
1200
+ 10000
1201
+ """
1202
+ count = 0
1203
+
1204
+ def incr(node):
1205
+ nonlocal count
1206
+ count += 1
1207
+
1208
+ self.iterative_pre_order_traversal(incr)
1209
+ return Integer(count)
1210
+
1211
+ def depth(self):
1212
+ """
1213
+ Return the depth of ``self``.
1214
+
1215
+ EXAMPLES::
1216
+
1217
+ sage: OrderedTree().depth()
1218
+ 1
1219
+ sage: OrderedTree([]).depth()
1220
+ 1
1221
+ sage: OrderedTree([[],[]]).depth()
1222
+ 2
1223
+ sage: OrderedTree([[],[[]]]).depth()
1224
+ 3
1225
+ sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).depth()
1226
+ 4
1227
+
1228
+ sage: BinaryTree().depth()
1229
+ 0
1230
+ sage: BinaryTree([[],[[],[]]]).depth()
1231
+ 3
1232
+
1233
+ TESTS:
1234
+
1235
+ Check that we do not hit a recursion limit::
1236
+
1237
+ sage: T = OrderedTree([])
1238
+ sage: for _ in range(9999):
1239
+ ....: T = OrderedTree([T])
1240
+ sage: T.depth()
1241
+ 10000
1242
+ """
1243
+ if self.is_empty():
1244
+ return 0
1245
+ m = []
1246
+
1247
+ def action(node):
1248
+ nonlocal m
1249
+ if node.is_empty():
1250
+ m.append(-1)
1251
+ elif not bool(node):
1252
+ m.append(0)
1253
+ else:
1254
+ mx = max(m.pop() for _ in node)
1255
+ m.append(mx + 1)
1256
+
1257
+ self.contour_traversal(final_action=action, leaf_action=action)
1258
+ return Integer(m[0] + 1)
1259
+
1260
+ def _ascii_art_(self):
1261
+ r"""
1262
+ TESTS::
1263
+
1264
+ sage: t = OrderedTree([])
1265
+ sage: ascii_art(t)
1266
+ o
1267
+ sage: t = OrderedTree([[]])
1268
+ sage: aa = ascii_art(t);aa
1269
+ o
1270
+ |
1271
+ o
1272
+ sage: aa.get_baseline()
1273
+ 2
1274
+ sage: tt1 = OrderedTree([[],[[],[],[[[[]]]]],[[[],[],[],[]]]])
1275
+ sage: ascii_art(tt1)
1276
+ _____o_______
1277
+ / / /
1278
+ o _o__ o
1279
+ / / / |
1280
+ o o o __o___
1281
+ | / / / /
1282
+ o o o o o
1283
+ |
1284
+ o
1285
+ |
1286
+ o
1287
+ sage: ascii_art(tt1.canonical_labelling())
1288
+ ______1_______
1289
+ / / /
1290
+ 2 _3__ 10
1291
+ / / / |
1292
+ 4 5 6 ___11____
1293
+ | / / / /
1294
+ 7 12 13 14 15
1295
+ |
1296
+ 8
1297
+ |
1298
+ 9
1299
+ sage: ascii_art(OrderedTree([[],[[]]]))
1300
+ o_
1301
+ / /
1302
+ o o
1303
+ |
1304
+ o
1305
+ sage: t = OrderedTree([[[],[[[],[]]],[[]]],[[[[[],[]]]]],[[],[]]])
1306
+ sage: ascii_art(t)
1307
+ _____o_______
1308
+ / / /
1309
+ __o____ o o_
1310
+ / / / | / /
1311
+ o o o o o o
1312
+ | | |
1313
+ o_ o o
1314
+ / / |
1315
+ o o o_
1316
+ / /
1317
+ o o
1318
+ sage: ascii_art(t.canonical_labelling())
1319
+ ______1________
1320
+ / / /
1321
+ __2____ 10 16_
1322
+ / / / | / /
1323
+ 3 4 8 11 17 18
1324
+ | | |
1325
+ 5_ 9 12
1326
+ / / |
1327
+ 6 7 13_
1328
+ / /
1329
+ 14 15
1330
+ """
1331
+ def node_to_str(t):
1332
+ return str(t.label()) if hasattr(t, "label") else "o"
1333
+
1334
+ if self.is_empty():
1335
+ from sage.typeset.ascii_art import empty_ascii_art
1336
+ return empty_ascii_art
1337
+
1338
+ from sage.typeset.ascii_art import AsciiArt
1339
+ if len(self) == 0:
1340
+ t_repr = AsciiArt([node_to_str(self)])
1341
+ t_repr._root = 1
1342
+ return t_repr
1343
+ if len(self) == 1:
1344
+ repr_child = self[0]._ascii_art_()
1345
+ sep = AsciiArt([" " * (repr_child._root - 1)])
1346
+ t_repr = AsciiArt([node_to_str(self)])
1347
+ t_repr._root = 1
1348
+ repr_root = (sep + t_repr) * (sep + AsciiArt(["|"]))
1349
+ t_repr = repr_root * repr_child
1350
+ t_repr._root = repr_child._root
1351
+ t_repr._baseline = t_repr._h - 1
1352
+ return t_repr
1353
+ # General case
1354
+ l_repr = [subtree._ascii_art_() for subtree in self]
1355
+ acc = l_repr.pop(0)
1356
+ whitesep = acc._root + 1
1357
+ lf_sep = " " * (acc._root + 1) + "_" * (acc._l - acc._root)
1358
+ ls_sep = " " * (acc._root) + "/" + " " * (acc._l - acc._root)
1359
+ while l_repr:
1360
+ t_repr = l_repr.pop(0)
1361
+ acc += AsciiArt([" "]) + t_repr
1362
+ if len(l_repr) == 0:
1363
+ lf_sep += "_" * (t_repr._root + 1)
1364
+ else:
1365
+ lf_sep += "_" * (t_repr._l + 1)
1366
+ ls_sep += " " * (t_repr._root) + "/" + " " * (t_repr._l - t_repr._root)
1367
+ mid = whitesep + (len(lf_sep) - whitesep) // 2
1368
+ node = node_to_str(self)
1369
+ t_repr = AsciiArt([lf_sep[:mid - 1] + node + lf_sep[mid + len(node) - 1:], ls_sep]) * acc
1370
+ t_repr._root = mid
1371
+ t_repr._baseline = t_repr._h - 1
1372
+ return t_repr
1373
+
1374
+ def _unicode_art_(self):
1375
+ r"""
1376
+ TESTS::
1377
+
1378
+ sage: t = OrderedTree([])
1379
+ sage: unicode_art(t)
1380
+ o
1381
+ sage: t = OrderedTree([[]])
1382
+ sage: aa = unicode_art(t);aa
1383
+ o
1384
+
1385
+ o
1386
+ sage: aa.get_baseline()
1387
+ 2
1388
+ sage: tt1 = OrderedTree([[],[[],[],[[[[]]]]],[[[],[],[],[]]]])
1389
+ sage: unicode_art(tt1)
1390
+ ╭───┬─o────╮
1391
+ │ │ │
1392
+ o ╭─o─╮ o
1393
+ │ │ │ │
1394
+ o o o ╭─┬o┬─╮
1395
+ │ │ │ │ │
1396
+ o o o o o
1397
+
1398
+ o
1399
+
1400
+ o
1401
+ sage: unicode_art(tt1.canonical_labelling())
1402
+ ╭───┬──1─────╮
1403
+ │ │ │
1404
+ 2 ╭─3─╮ 10
1405
+ │ │ │ │
1406
+ 4 5 6 ╭──┬11┬──╮
1407
+ │ │ │ │ │
1408
+ 7 12 13 14 15
1409
+
1410
+ 8
1411
+
1412
+ 9
1413
+ sage: unicode_art(OrderedTree([[],[[]]]))
1414
+ ╭o╮
1415
+ │ │
1416
+ o o
1417
+
1418
+ o
1419
+ sage: t = OrderedTree([[[],[[[],[]]],[[]]],[[[[[],[]]]]],[[],[]]])
1420
+ sage: unicode_art(t)
1421
+ ╭────o┬───╮
1422
+ │ │ │
1423
+ ╭──o──╮ o ╭o╮
1424
+ │ │ │ │ │ │
1425
+ o o o o o o
1426
+ │ │ │
1427
+ ╭o╮ o o
1428
+ │ │ │
1429
+ o o ╭o╮
1430
+ │ │
1431
+ o o
1432
+ sage: unicode_art(t.canonical_labelling())
1433
+ ╭──────1─────╮
1434
+ │ │ │
1435
+ ╭──2──╮ 10 ╭16╮
1436
+ │ │ │ │ │ │
1437
+ 3 4 8 11 17 18
1438
+ │ │ │
1439
+ ╭5╮ 9 12
1440
+ │ │ │
1441
+ 6 7 ╭13╮
1442
+ │ │
1443
+ 14 15
1444
+ """
1445
+
1446
+ def node_to_str(t):
1447
+ if hasattr(t, "label"):
1448
+ return str(t.label())
1449
+ else:
1450
+ return "o"
1451
+ # other possible choices for nodes would be u"█ ▓ ░ ╋ ╬"
1452
+
1453
+ if self.is_empty():
1454
+ from sage.typeset.unicode_art import empty_unicode_art
1455
+ return empty_unicode_art
1456
+
1457
+ from sage.typeset.unicode_art import UnicodeArt
1458
+ if not len(self):
1459
+ t_repr = UnicodeArt([node_to_str(self)])
1460
+ t_repr._root = 0
1461
+ return t_repr
1462
+
1463
+ if len(self) == 1:
1464
+ repr_child = self[0]._unicode_art_()
1465
+ sep = UnicodeArt([" " * repr_child._root])
1466
+ t_repr = UnicodeArt([node_to_str(self)])
1467
+ repr_root = (sep + t_repr) * (sep + UnicodeArt(["│"]))
1468
+ t_repr = repr_root * repr_child
1469
+ t_repr._root = repr_child._root
1470
+ t_repr._baseline = t_repr._h - 1
1471
+ return t_repr
1472
+
1473
+ # General case
1474
+ l_repr = [subtree._unicode_art_() for subtree in self]
1475
+ acc = l_repr.pop(0)
1476
+ whitesep = acc._root
1477
+ lf_sep = " " * whitesep + "╭" + "─" * (acc._l - acc._root)
1478
+ ls_sep = " " * whitesep + "│" + " " * (acc._l - acc._root)
1479
+ while l_repr:
1480
+ tr = l_repr.pop(0)
1481
+ acc += UnicodeArt([" "]) + tr
1482
+ if not l_repr:
1483
+ lf_sep += "─" * (tr._root) + "╮"
1484
+ ls_sep += " " * (tr._root) + "│"
1485
+ else:
1486
+ lf_sep += "─" * (tr._root) + "┬" + "─" * (tr._l - tr._root)
1487
+ ls_sep += " " * (tr._root) + "│" + " " * (tr._l - tr._root)
1488
+ mid = whitesep + (len(lf_sep) - whitesep) // 2
1489
+ node = node_to_str(self)
1490
+ lf_sep = (lf_sep[:mid - len(node) // 2] + node +
1491
+ lf_sep[mid + len(node) - len(node) // 2:])
1492
+ t_repr = UnicodeArt([lf_sep, ls_sep]) * acc
1493
+ t_repr._root = mid
1494
+ t_repr._baseline = t_repr._h - 1
1495
+ return t_repr
1496
+
1497
+ def canonical_labelling(self, shift=1):
1498
+ """
1499
+ Return a labelled version of ``self``.
1500
+
1501
+ The actual canonical labelling is currently unspecified. However, it
1502
+ is guaranteed to have labels in `1...n` where `n` is the number of
1503
+ nodes of the tree. Moreover, two (unlabelled) trees compare as equal if
1504
+ and only if their canonical labelled trees compare as equal.
1505
+
1506
+ EXAMPLES::
1507
+
1508
+ sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]])
1509
+ sage: t.canonical_labelling()
1510
+ 1[2[], 3[4[], 5[6[], 7[]], 8[9[], 10[]]], 11[12[], 13[]]]
1511
+
1512
+ sage: BinaryTree([]).canonical_labelling()
1513
+ 1[., .]
1514
+ sage: BinaryTree([[],[[],[]]]).canonical_labelling()
1515
+ 2[1[., .], 4[3[., .], 5[., .]]]
1516
+
1517
+ TESTS::
1518
+
1519
+ sage: BinaryTree().canonical_labelling()
1520
+ .
1521
+ """
1522
+ LTR = self.parent().labelled_trees()
1523
+ liste = []
1524
+ deca = 1
1525
+ for subtree in self:
1526
+ liste += [subtree.canonical_labelling(shift + deca)]
1527
+ deca += subtree.node_number()
1528
+ return LTR._element_constructor_(liste, label=shift)
1529
+
1530
+ def to_hexacode(self):
1531
+ r"""
1532
+ Transform a tree into a hexadecimal string.
1533
+
1534
+ The definition of the hexacode is recursive. The first letter is
1535
+ the valence of the root as a hexadecimal (up to 15), followed by
1536
+ the concatenation of the hexacodes of the subtrees.
1537
+
1538
+ This method only works for trees where every vertex has
1539
+ valency at most 15.
1540
+
1541
+ See :func:`from_hexacode` for the reverse transformation.
1542
+
1543
+ EXAMPLES::
1544
+
1545
+ sage: from sage.combinat.abstract_tree import from_hexacode
1546
+ sage: LT = LabelledOrderedTrees()
1547
+ sage: from_hexacode('2010', LT).to_hexacode()
1548
+ '2010'
1549
+ sage: LT.an_element().to_hexacode()
1550
+ '3020010'
1551
+ sage: t = from_hexacode('a0000000000000000', LT)
1552
+ sage: t.to_hexacode()
1553
+ 'a0000000000'
1554
+
1555
+ sage: OrderedTrees(6).an_element().to_hexacode()
1556
+ '500000'
1557
+
1558
+ TESTS::
1559
+
1560
+ sage: one = LT([], label='@')
1561
+ sage: LT([one for _ in range(15)], label='@').to_hexacode()
1562
+ 'f000000000000000'
1563
+ sage: LT([one for _ in range(16)], label='@').to_hexacode()
1564
+ Traceback (most recent call last):
1565
+ ...
1566
+ ValueError: the width of the tree is too large
1567
+ """
1568
+ if len(self) > 15:
1569
+ raise ValueError("the width of the tree is too large")
1570
+ if self.node_number() == 1:
1571
+ return "0"
1572
+ return ("%x" % len(self)) + "".join(u.to_hexacode() for u in self)
1573
+
1574
+ def tree_factorial(self):
1575
+ r"""
1576
+ Return the tree-factorial of ``self``.
1577
+
1578
+ Definition:
1579
+
1580
+ The tree-factorial `T!` of a tree `T` is the product `\prod_{v\in
1581
+ T}\#\mbox{children}(v)`.
1582
+
1583
+ EXAMPLES::
1584
+
1585
+ sage: LT = LabelledOrderedTrees()
1586
+ sage: t = LT([LT([],label=6),LT([],label=1)],label=9)
1587
+ sage: t.tree_factorial()
1588
+ 3
1589
+
1590
+ sage: BinaryTree([[],[[],[]]]).tree_factorial()
1591
+ 15
1592
+
1593
+ TESTS::
1594
+
1595
+ sage: BinaryTree().tree_factorial()
1596
+ 1
1597
+ """
1598
+ nb = self.node_number()
1599
+ if nb <= 1:
1600
+ return Integer(1)
1601
+ return nb * prod(s.tree_factorial() for s in self)
1602
+
1603
+ def _latex_(self):
1604
+ r"""
1605
+ Generate `\LaTeX` output which can be easily modified.
1606
+
1607
+ TESTS::
1608
+
1609
+ sage: latex(BinaryTree([[[],[]],[[],None]]))
1610
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1611
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$$}
1612
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$$}
1613
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$$}
1614
+ ;}\newcommand{\nodee}{\node[draw,circle] (e) {$$}
1615
+ ;}\newcommand{\nodef}{\node[draw,circle] (f) {$$}
1616
+ ;}\begin{tikzpicture}[auto]
1617
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1618
+ \& \& \& \nodea \& \& \& \\
1619
+ \& \nodeb \& \& \& \& \nodee \& \\
1620
+ \nodec \& \& \noded \& \& \nodef \& \& \\
1621
+ };
1622
+ <BLANKLINE>
1623
+ \path[ultra thick, red] (b) edge (c) edge (d)
1624
+ (e) edge (f)
1625
+ (a) edge (b) edge (e);
1626
+ \end{tikzpicture}}
1627
+ """
1628
+ #######################################################################
1629
+ # load tikz in the preamble for *view*
1630
+ from sage.misc.latex import latex
1631
+ latex.add_package_to_preamble_if_available("tikz")
1632
+ #######################################################################
1633
+ # latex environment : TikZ
1634
+ begin_env = "\\begin{tikzpicture}[auto]\n"
1635
+ end_env = "\\end{tikzpicture}"
1636
+ # it uses matrix trick to place each node
1637
+ matrix_begin = "\\matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\\&]{\n"
1638
+ matrix_end = "\\\\\n};\n"
1639
+ # a basic path to each edges
1640
+ path_begin = "\\path[ultra thick, red] "
1641
+ path_end = ";\n"
1642
+ # to make a pretty output, it creates one LaTeX command for
1643
+ # each node
1644
+ cmd = "\\node"
1645
+ new_cmd1 = "\\newcommand{" + cmd
1646
+ new_cmd2 = "}{\\node[draw,circle] ("
1647
+ new_cmd3 = ") {$"
1648
+ new_cmd4 = "$}\n;}"
1649
+ # some variables to simplify code
1650
+ sep = "\\&"
1651
+ space = " " * 9
1652
+ sepspace = sep + space
1653
+ spacesep = space + sep
1654
+
1655
+ def node_to_str(node):
1656
+ return " " + node + " " * (len(space) - 1 - len(node))
1657
+ # # TODO:: modify how to create nodes --> new_cmd : \\node[...] in create_node
1658
+ num = [0]
1659
+
1660
+ def resolve(self):
1661
+ nodes = []
1662
+ matrix = []
1663
+ edges = []
1664
+
1665
+ def create_node(self):
1666
+ r"""
1667
+ create a name (infixe reading)
1668
+ -> ex: b
1669
+ create a new command:
1670
+ -> ex: \newcommand{\nodeb}{\node[draw,circle] (b) {$$};
1671
+ return the name and the command to build:
1672
+ . the matrix
1673
+ . and the edges
1674
+ """
1675
+ name = "".join(chr(ord(x) + 49) for x in str(num[0]))
1676
+ node = cmd + name
1677
+ nodes.append((name,
1678
+ (str(self.label()) if hasattr(self, "label") else ""))
1679
+ )
1680
+ num[0] += 1
1681
+ return node, name
1682
+
1683
+ def empty_tree():
1684
+ r"""
1685
+ TESTS::
1686
+
1687
+ sage: t = BinaryTree()
1688
+ sage: print(latex(t))
1689
+ { \begin{tikzpicture}[auto]
1690
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1691
+ \\
1692
+ };
1693
+ \end{tikzpicture}}
1694
+ """
1695
+ matrix.append(space)
1696
+
1697
+ def one_node_tree(self):
1698
+ r"""
1699
+ TESTS::
1700
+
1701
+ sage: t = BinaryTree([]); print(latex(t))
1702
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1703
+ ;}\begin{tikzpicture}[auto]
1704
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1705
+ \nodea \\
1706
+ };
1707
+ \end{tikzpicture}}
1708
+ sage: t = OrderedTree([]); print(latex(t))
1709
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1710
+ ;}\begin{tikzpicture}[auto]
1711
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1712
+ \nodea \\
1713
+ };
1714
+ \end{tikzpicture}}
1715
+ """
1716
+ node, _ = create_node(self)
1717
+ matrix.append(node_to_str(node))
1718
+
1719
+ def concat_matrix(mat, mat2):
1720
+ lmat = len(mat)
1721
+ lmat2 = len(mat2)
1722
+ for i in range(max(lmat, lmat2)):
1723
+ # mat[i] --> n & n & ...
1724
+ # mat2[i] -> n' & n' & ...
1725
+ # ==> n & n & ... & n' & n' & ...
1726
+ try:
1727
+ mat[i] += sep + mat2[i]
1728
+ except IndexError:
1729
+ if i >= lmat:
1730
+ if i != 0:
1731
+ # mat[i] does not exist but
1732
+ # mat[0] has k "&"
1733
+ # mat2[i] -> n' & n' & ...
1734
+ # ==> (_ &)*k+1 n' & n' & ...
1735
+ nb_of_and = mat[0].count(sep) - mat2[0].count(sep)
1736
+ mat.append(spacesep * (nb_of_and) + mat2[i])
1737
+ else:
1738
+ # mat is empty
1739
+ # mat2[i] -> n' & n' & ...
1740
+ # ==> mat2
1741
+ mat.extend(mat2)
1742
+ return
1743
+ else:
1744
+ # mat[i] -> n & n & ...
1745
+ # mat2[i] does not exist but mat2[0] exists
1746
+ # # and has k "&"
1747
+ # NOTE:: i != 0 because that is a no-empty subtree.
1748
+ # ==> n & n & ... (& _)*k+1
1749
+ nb_of_and = mat2[0].count(sep)
1750
+ mat[i] += sepspace * (nb_of_and + 1)
1751
+
1752
+ def tmp(subtree, edge, nodes, edges, matrix):
1753
+ if not subtree.is_empty():
1754
+ # # create representation of the subtree
1755
+ nodes_st, matrix_st, edges_st = resolve(subtree)
1756
+ # # add its nodes to the "global" nodes set
1757
+ nodes.extend(nodes_st)
1758
+ # # create a new edge between the root and the subtree
1759
+ edge.append(nodes_st[0][0])
1760
+ # # add the subtree edges to the "global" edges set
1761
+ edges.extend(edges_st)
1762
+ # # build a new matrix by concatenation
1763
+ concat_matrix(matrix, matrix_st)
1764
+ else:
1765
+ concat_matrix(matrix, [space])
1766
+
1767
+ def pair_nodes_tree(self, nodes, edges, matrix):
1768
+ r"""
1769
+ TESTS::
1770
+
1771
+ sage: t = OrderedTree([[[],[]],[[],[]]]).\
1772
+ ....: canonical_labelling(); print(latex(t))
1773
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1774
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1775
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1776
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1777
+ ;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1778
+ ;}\newcommand{\nodef}{\node[draw,circle] (f) {$6$}
1779
+ ;}\newcommand{\nodeg}{\node[draw,circle] (g) {$7$}
1780
+ ;}\begin{tikzpicture}[auto]
1781
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1782
+ \& \& \& \nodea \& \& \& \\
1783
+ \& \nodeb \& \& \& \& \nodee \& \\
1784
+ \nodec \& \& \noded \& \& \nodef \& \& \nodeg \\
1785
+ };
1786
+ <BLANKLINE>
1787
+ \path[ultra thick, red] (b) edge (c) edge (d)
1788
+ (e) edge (f) edge (g)
1789
+ (a) edge (b) edge (e);
1790
+ \end{tikzpicture}}
1791
+ sage: t = BinaryTree([[],[[],[]]]); print(latex(t))
1792
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$$}
1793
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$$}
1794
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$$}
1795
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$$}
1796
+ ;}\newcommand{\nodee}{\node[draw,circle] (e) {$$}
1797
+ ;}\begin{tikzpicture}[auto]
1798
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1799
+ \& \nodea \& \& \& \\
1800
+ \nodeb \& \& \& \nodec \& \\
1801
+ \& \& \noded \& \& \nodee \\
1802
+ };
1803
+ <BLANKLINE>
1804
+ \path[ultra thick, red] (c) edge (d) edge (e)
1805
+ (a) edge (b) edge (c);
1806
+ \end{tikzpicture}}
1807
+ """
1808
+ # build all subtree matrices.
1809
+ node, name = create_node(self)
1810
+ edge = [name]
1811
+ split = len(self) // 2
1812
+ # the left part
1813
+ for i in range(split):
1814
+ tmp(self[i], edge, nodes, edges, matrix)
1815
+ # # prepare the root line
1816
+ nb_of_and = matrix[0].count(sep)
1817
+ # the middle
1818
+ for i in range(len(matrix)):
1819
+ matrix[i] += sepspace
1820
+ # the right part
1821
+ for i in range(split, len(self)):
1822
+ tmp(self[i], edge, nodes, edges, matrix)
1823
+
1824
+ # # create the root line
1825
+ root_line = (spacesep * (nb_of_and + 1) + node_to_str(node) +
1826
+ sepspace * (matrix[0].count(sep) - nb_of_and - 1))
1827
+ matrix.insert(0, root_line)
1828
+ # add edges from the root
1829
+ edges.append(edge)
1830
+
1831
+ def odd_nodes_tree(self, nodes, edges, matrix):
1832
+ r"""
1833
+ TESTS::
1834
+
1835
+ sage: t = OrderedTree([[]]).canonical_labelling()
1836
+ sage: print(latex(t))
1837
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1838
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1839
+ ;}\begin{tikzpicture}[auto]
1840
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1841
+ \nodea \\
1842
+ \nodeb \\
1843
+ };
1844
+ <BLANKLINE>
1845
+ \path[ultra thick, red] (a) edge (b);
1846
+ \end{tikzpicture}}
1847
+ sage: t = OrderedTree([[[],[]]]).canonical_labelling(); print(latex(t))
1848
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1849
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1850
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1851
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1852
+ ;}\begin{tikzpicture}[auto]
1853
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1854
+ \& \nodea \& \\
1855
+ \& \nodeb \& \\
1856
+ \nodec \& \& \noded \\
1857
+ };
1858
+ <BLANKLINE>
1859
+ \path[ultra thick, red] (b) edge (c) edge (d)
1860
+ (a) edge (b);
1861
+ \end{tikzpicture}}
1862
+ sage: t = OrderedTree([[[],[],[]]]).canonical_labelling(); print(latex(t))
1863
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1864
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1865
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1866
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1867
+ ;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1868
+ ;}\begin{tikzpicture}[auto]
1869
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1870
+ \& \nodea \& \\
1871
+ \& \nodeb \& \\
1872
+ \nodec \& \noded \& \nodee \\
1873
+ };
1874
+ <BLANKLINE>
1875
+ \path[ultra thick, red] (b) edge (c) edge (d) edge (e)
1876
+ (a) edge (b);
1877
+ \end{tikzpicture}}
1878
+ sage: t = OrderedTree([[[],[],[]],[],[]]).canonical_labelling(); print(latex(t))
1879
+ { \newcommand{\nodea}{\node[draw,circle] (a) {$1$}
1880
+ ;}\newcommand{\nodeb}{\node[draw,circle] (b) {$2$}
1881
+ ;}\newcommand{\nodec}{\node[draw,circle] (c) {$3$}
1882
+ ;}\newcommand{\noded}{\node[draw,circle] (d) {$4$}
1883
+ ;}\newcommand{\nodee}{\node[draw,circle] (e) {$5$}
1884
+ ;}\newcommand{\nodef}{\node[draw,circle] (f) {$6$}
1885
+ ;}\newcommand{\nodeg}{\node[draw,circle] (g) {$7$}
1886
+ ;}\begin{tikzpicture}[auto]
1887
+ \matrix[column sep=.3cm, row sep=.3cm,ampersand replacement=\&]{
1888
+ \& \& \& \nodea \& \\
1889
+ \& \nodeb \& \& \nodef \& \nodeg \\
1890
+ \nodec \& \noded \& \nodee \& \& \\
1891
+ };
1892
+ <BLANKLINE>
1893
+ \path[ultra thick, red] (b) edge (c) edge (d) edge (e)
1894
+ (a) edge (b) edge (f) edge (g);
1895
+ \end{tikzpicture}}
1896
+ """
1897
+ # build all subtree matrices.
1898
+ node, name = create_node(self)
1899
+ edge = [name]
1900
+ split = len(self) // 2
1901
+ # the left part
1902
+ for i in range(split):
1903
+ tmp(self[i], edge, nodes, edges, matrix)
1904
+ # # prepare the root line
1905
+ if matrix:
1906
+ nb_of_and = matrix[0].count(sep)
1907
+ sizetmp = len(matrix[0])
1908
+ else:
1909
+ nb_of_and = 0
1910
+ sizetmp = 0
1911
+ # the middle
1912
+ tmp(self[split], edge, nodes, edges, matrix)
1913
+ nb_of_and += matrix[0][sizetmp:].split("node")[0].count(sep)
1914
+
1915
+ # the right part
1916
+ for i in range(split + 1, len(self)):
1917
+ tmp(self[i], edge, nodes, edges, matrix)
1918
+
1919
+ # # create the root line
1920
+ root_line = (spacesep * (nb_of_and) + node_to_str(node) +
1921
+ sepspace * (matrix[0].count(sep) - nb_of_and))
1922
+ matrix.insert(0, root_line)
1923
+ # add edges from the root
1924
+ edges.append(edge)
1925
+ if self.is_empty():
1926
+ empty_tree()
1927
+ elif len(self) == 0 or all(subtree.is_empty()
1928
+ for subtree in self):
1929
+ one_node_tree(self)
1930
+ elif not len(self) % 2:
1931
+ pair_nodes_tree(self, nodes, edges, matrix)
1932
+ else:
1933
+ odd_nodes_tree(self, nodes, edges, matrix)
1934
+ return nodes, matrix, edges
1935
+
1936
+ nodes, matrix, edges = resolve(self)
1937
+
1938
+ def make_cmd(nodes):
1939
+ cmds = []
1940
+ for name, label in nodes:
1941
+ cmds.append(new_cmd1 + name + new_cmd2 +
1942
+ name + new_cmd3 +
1943
+ label + new_cmd4)
1944
+ return cmds
1945
+
1946
+ def make_edges(edges):
1947
+ all_paths = []
1948
+ for edge in edges:
1949
+ path = "(" + edge[0] + ")"
1950
+ for i in range(1, len(edge)):
1951
+ path += " edge (%s)" % edge[i]
1952
+ all_paths.append(path)
1953
+ return all_paths
1954
+ return ("{ " +
1955
+ "".join(make_cmd(nodes)) +
1956
+ begin_env +
1957
+ (matrix_begin +
1958
+ "\\\\ \n".join(matrix) +
1959
+ matrix_end +
1960
+ ("\n" +
1961
+ path_begin +
1962
+ "\n\t".join(make_edges(edges)) +
1963
+ path_end if edges else "")
1964
+ if matrix else "") +
1965
+ end_env +
1966
+ "}")
1967
+
1968
+
1969
+ class AbstractClonableTree(AbstractTree):
1970
+ """
1971
+ Abstract Clonable Tree.
1972
+
1973
+ An abstract class for trees with clone protocol (see
1974
+ :mod:`~sage.structure.list_clone`). It is expected that classes extending
1975
+ this one may also inherit from classes like :class:`~sage.structure.list_clone.ClonableArray` or
1976
+ :class:`~sage.structure.list_clone.ClonableList` depending whether one
1977
+ wants to build trees where adding a child is allowed.
1978
+
1979
+ .. NOTE:: Due to the limitation of Cython inheritance, one cannot inherit
1980
+ here from :class:`~sage.structure.list_clone.ClonableElement`, because
1981
+ it would prevent us from later inheriting from
1982
+ :class:`~sage.structure.list_clone.ClonableArray` or
1983
+ :class:`~sage.structure.list_clone.ClonableList`.
1984
+
1985
+ .. rubric:: How should this class be extended ?
1986
+
1987
+ A class extending :class:`AbstractClonableTree
1988
+ <sage.combinat.abstract_tree.AbstractClonableTree>` should satisfy the
1989
+ following assumptions:
1990
+
1991
+ * An instantiable class extending :class:`AbstractClonableTree
1992
+ <sage.combinat.abstract_tree.AbstractClonableTree>` should also extend
1993
+ the :class:`ClonableElement <sage.structure.list_clone.ClonableElement>`
1994
+ class or one of its subclasses generally, at least :class:`ClonableArray
1995
+ <sage.structure.list_clone.ClonableArray>`.
1996
+
1997
+ * To respect the Clone protocol, the :meth:`AbstractClonableTree.check`
1998
+ method should be overridden by the new class.
1999
+
2000
+ See also the assumptions in :class:`AbstractTree`.
2001
+ """
2002
+
2003
+ def check(self):
2004
+ """
2005
+ Check that ``self`` is a correct tree.
2006
+
2007
+ This method does nothing. It is implemented here because many
2008
+ extensions of :class:`AbstractClonableTree
2009
+ <sage.combinat.abstract_tree.AbstractClonableTree>` also extend
2010
+ :class:`sage.structure.list_clone.ClonableElement`, which requires it.
2011
+
2012
+ It should be overridden in subclasses in order to check that the
2013
+ characterizing property of the respective kind of tree holds (eg: two
2014
+ children for binary trees).
2015
+
2016
+ EXAMPLES::
2017
+
2018
+ sage: OrderedTree([[],[[]]]).check()
2019
+ sage: BinaryTree([[],[[],[]]]).check()
2020
+ """
2021
+ pass
2022
+
2023
+ def __setitem__(self, idx, value):
2024
+ """
2025
+ Substitute a subtree.
2026
+
2027
+ .. NOTE::
2028
+
2029
+ The tree ``self`` must be in a mutable state. See
2030
+ :mod:`sage.structure.list_clone` for more details about
2031
+ mutability. The default implementation here assume that the
2032
+ container of the node implement a method ``_setitem`` with signature
2033
+ `self._setitem(idx, value)`. It is usually provided by inheriting
2034
+ from :class:`~sage.structure.list_clone.ClonableArray`.
2035
+
2036
+ INPUT:
2037
+
2038
+ - ``idx`` -- a valid path in ``self`` identifying a node
2039
+
2040
+ - ``value`` -- the tree to be substituted
2041
+
2042
+ EXAMPLES:
2043
+
2044
+ Trying to modify a non mutable tree raises an error::
2045
+
2046
+ sage: x = OrderedTree([])
2047
+ sage: x[0] = OrderedTree([[]])
2048
+ Traceback (most recent call last):
2049
+ ...
2050
+ ValueError: object is immutable; please change a copy instead.
2051
+
2052
+ Here is the correct way to do it::
2053
+
2054
+ sage: x = OrderedTree([[],[[]]])
2055
+ sage: with x.clone() as x:
2056
+ ....: x[0] = OrderedTree([[]])
2057
+ sage: x
2058
+ [[[]], [[]]]
2059
+
2060
+ One can also substitute at any depth::
2061
+
2062
+ sage: y = OrderedTree(x)
2063
+ sage: with x.clone() as x:
2064
+ ....: x[0,0] = OrderedTree([[]])
2065
+ sage: x
2066
+ [[[[]]], [[]]]
2067
+ sage: y
2068
+ [[[]], [[]]]
2069
+ sage: with y.clone() as y:
2070
+ ....: y[(0,)] = OrderedTree([])
2071
+ sage: y
2072
+ [[], [[]]]
2073
+
2074
+ This works for binary trees as well::
2075
+
2076
+ sage: bt = BinaryTree([[],[[],[]]]); bt
2077
+ [[., .], [[., .], [., .]]]
2078
+ sage: with bt.clone() as bt1:
2079
+ ....: bt1[0,0] = BinaryTree([[[], []], None])
2080
+ sage: bt1
2081
+ [[[[[., .], [., .]], .], .], [[., .], [., .]]]
2082
+
2083
+ TESTS::
2084
+
2085
+ sage: x = OrderedTree([])
2086
+ sage: with x.clone() as x:
2087
+ ....: x[0] = OrderedTree([[]])
2088
+ Traceback (most recent call last):
2089
+ ...
2090
+ IndexError: list assignment index out of range
2091
+
2092
+ sage: x = OrderedTree([]); x = OrderedTree([x,x]); x = OrderedTree([x,x]); x = OrderedTree([x,x])
2093
+ sage: with x.clone() as x:
2094
+ ....: x[0,0] = OrderedTree()
2095
+ sage: x
2096
+ [[[], [[], []]], [[[], []], [[], []]]]
2097
+ """
2098
+ if not isinstance(value, self.__class__):
2099
+ raise TypeError('the given value is not a tree')
2100
+ if isinstance(idx, tuple):
2101
+ self.__setitem_rec__(idx, 0, value)
2102
+ else:
2103
+ self._setitem(idx, value)
2104
+
2105
+ def __setitem_rec__(self, idx, i, value):
2106
+ """
2107
+ TESTS::
2108
+
2109
+ sage: x = OrderedTree([[[], []],[[]]])
2110
+ sage: with x.clone() as x: # indirect doctest
2111
+ ....: x[0,1] = OrderedTree([[[]]])
2112
+ sage: x
2113
+ [[[], [[[]]]], [[]]]
2114
+ """
2115
+ if i == len(idx) - 1:
2116
+ self._setitem(idx[-1], value)
2117
+ else:
2118
+ with self[idx[i]].clone() as child:
2119
+ child.__setitem_rec__(idx, i + 1, value)
2120
+ self[idx[i]] = child
2121
+
2122
+ def __getitem__(self, idx):
2123
+ """
2124
+ Return the ``idx``-th child of ``self`` (which is a subtree) if
2125
+ ``idx`` is an integer, or the ``idx[n-1]``-th child of the
2126
+ ``idx[n-2]``-th child of the ... of the ``idx[0]``-th child of
2127
+ ``self`` if ``idx`` is a list (or iterable) of length `n`.
2128
+
2129
+ The indexing of the children is zero-based.
2130
+
2131
+ INPUT:
2132
+
2133
+ - ``idx`` -- integer; or a valid path in ``self`` identifying a node
2134
+
2135
+ .. NOTE::
2136
+
2137
+ The default implementation here assumes that the container of the
2138
+ node inherits from
2139
+ :class:`~sage.structure.list_clone.ClonableArray`.
2140
+
2141
+ EXAMPLES::
2142
+
2143
+ sage: x = OrderedTree([[],[[]]])
2144
+ sage: x[1,0]
2145
+ []
2146
+ sage: x = OrderedTree([[],[[]]])
2147
+ sage: x[()]
2148
+ [[], [[]]]
2149
+ sage: x[(0,)]
2150
+ []
2151
+ sage: x[0,0]
2152
+ Traceback (most recent call last):
2153
+ ...
2154
+ IndexError: list index out of range
2155
+
2156
+ sage: u = BinaryTree(None)
2157
+ sage: v = BinaryTree([u, u])
2158
+ sage: w = BinaryTree([u, v])
2159
+ sage: t = BinaryTree([v, w])
2160
+ sage: z = BinaryTree([w, t])
2161
+ sage: z[0,1]
2162
+ [., .]
2163
+ sage: z[0,0]
2164
+ .
2165
+ sage: z[1]
2166
+ [[., .], [., [., .]]]
2167
+ sage: z[1,1]
2168
+ [., [., .]]
2169
+ sage: z[1][1,1]
2170
+ [., .]
2171
+ """
2172
+ if isinstance(idx, slice):
2173
+ return ClonableArray.__getitem__(self, idx)
2174
+ try:
2175
+ i = int(idx)
2176
+ except TypeError:
2177
+ res = self
2178
+ # idx is supposed to be an iterable of ints
2179
+ for i in idx:
2180
+ res = ClonableArray._getitem(res, i)
2181
+ return res
2182
+ else:
2183
+ return ClonableArray._getitem(self, i)
2184
+
2185
+
2186
+ class AbstractLabelledTree(AbstractTree):
2187
+ """
2188
+ Abstract Labelled Tree.
2189
+
2190
+ Typically a class for labelled trees is constructed by inheriting from
2191
+ a class for unlabelled trees and :class:`AbstractLabelledTree`.
2192
+
2193
+ .. rubric:: How should this class be extended ?
2194
+
2195
+ A class extending :class:`AbstractLabelledTree
2196
+ <sage.combinat.abstract_tree.AbstractLabelledTree>` should respect the
2197
+ following assumptions:
2198
+
2199
+ * For a labelled tree ``T`` the call ``T.parent().unlabelled_trees()``
2200
+ should return a parent for unlabelled trees of the same kind: for
2201
+ example,
2202
+
2203
+ - if ``T`` is a binary labelled tree, ``T.parent()`` is
2204
+ ``LabelledBinaryTrees()`` and ``T.parent().unlabelled_trees()`` is
2205
+ ``BinaryTrees()``
2206
+
2207
+ - if ``T`` is an ordered labelled tree, ``T.parent()`` is
2208
+ ``LabelledOrderedTrees()`` and ``T.parent().unlabelled_trees()`` is
2209
+ ``OrderedTrees()``
2210
+
2211
+ * In the same vein, the class of ``T`` should contain an attribute
2212
+ ``_UnLabelled`` which should be the class for the corresponding
2213
+ unlabelled trees.
2214
+
2215
+ See also the assumptions in :class:`AbstractTree`.
2216
+
2217
+ .. SEEALSO:: :class:`AbstractTree`
2218
+ """
2219
+
2220
+ def __init__(self, parent, children, label=None, check=True):
2221
+ """
2222
+ TESTS::
2223
+
2224
+ sage: LabelledOrderedTree([])
2225
+ None[]
2226
+ sage: LabelledOrderedTree([], 3)
2227
+ 3[]
2228
+ sage: LT = LabelledOrderedTree
2229
+ sage: t = LT([LT([LT([], label=42), LT([], 21)])], label=1)
2230
+ sage: t
2231
+ 1[None[42[], 21[]]]
2232
+ sage: LabelledOrderedTree(OrderedTree([[],[[],[]],[]]))
2233
+ None[None[], None[None[], None[]], None[]]
2234
+
2235
+ We test that inheriting from `LabelledOrderedTree` allows construction from a
2236
+ `LabelledOrderedTree` (:issue:`16314`)::
2237
+
2238
+ sage: LBTS = LabelledOrderedTrees()
2239
+ sage: class Foo(LabelledOrderedTree):
2240
+ ....: def bar(self):
2241
+ ....: print("bar called")
2242
+ sage: foo = Foo(LBTS, [], label=1); foo
2243
+ 1[]
2244
+ sage: foo1 = LBTS([LBTS([], label=21)], label=42); foo1
2245
+ 42[21[]]
2246
+ sage: foo2 = Foo(LBTS, foo1); foo2
2247
+ 42[21[]]
2248
+ sage: foo2[0]
2249
+ 21[]
2250
+ sage: foo2.__class__
2251
+ <class '__main__.Foo'>
2252
+ sage: foo2[0].__class__
2253
+ <class '__main__.Foo'>
2254
+ sage: foo2.bar()
2255
+ bar called
2256
+ sage: foo2.label()
2257
+ 42
2258
+ """
2259
+ # We must initialize the label before the subtrees to allows rooted
2260
+ # trees canonization. Indeed it needs that ``self``._hash_() is working
2261
+ # at the end of the call super().__init__(...)
2262
+ if isinstance(children, AbstractLabelledTree):
2263
+ if label is None:
2264
+ self._label = children._label
2265
+ else:
2266
+ self._label = label
2267
+ else:
2268
+ self._label = label
2269
+ super().__init__(parent, children, check=check)
2270
+
2271
+ def _repr_(self):
2272
+ """
2273
+ Return the string representation of ``self``.
2274
+
2275
+ TESTS::
2276
+
2277
+ sage: LabelledOrderedTree([]) # indirect doctest
2278
+ None[]
2279
+ sage: LabelledOrderedTree([], label=3) # indirect doctest
2280
+ 3[]
2281
+ sage: LabelledOrderedTree([[],[[]]]) # indirect doctest
2282
+ None[None[], None[None[]]]
2283
+ sage: LabelledOrderedTree([[],LabelledOrderedTree([[]], label=2)], label=3)
2284
+ 3[None[], 2[None[]]]
2285
+ """
2286
+ return "%s%s" % (self._label, self[:])
2287
+
2288
+ def label(self, path=None):
2289
+ """
2290
+ Return the label of ``self``.
2291
+
2292
+ INPUT:
2293
+
2294
+ - ``path`` -- ``None`` (default) or a path (list or tuple of
2295
+ children index in the tree)
2296
+
2297
+ OUTPUT: the label of the subtree indexed by ``path``
2298
+
2299
+ EXAMPLES::
2300
+
2301
+ sage: t = LabelledOrderedTree([[],[]], label = 3)
2302
+ sage: t.label()
2303
+ 3
2304
+ sage: t[0].label()
2305
+ sage: t = LabelledOrderedTree([LabelledOrderedTree([], 5),[]], label = 3)
2306
+ sage: t.label()
2307
+ 3
2308
+ sage: t[0].label()
2309
+ 5
2310
+ sage: t[1].label()
2311
+ sage: t.label([0])
2312
+ 5
2313
+ """
2314
+ if path is None:
2315
+ return self._label
2316
+ else:
2317
+ tr = self
2318
+ for i in path:
2319
+ tr = tr[i]
2320
+ return tr._label
2321
+
2322
+ def labels(self):
2323
+ """
2324
+ Return the list of labels of ``self``.
2325
+
2326
+ EXAMPLES::
2327
+
2328
+ sage: LT = LabelledOrderedTree
2329
+ sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
2330
+ sage: t.labels()
2331
+ ['a', 'b', 'c']
2332
+
2333
+ sage: LBT = LabelledBinaryTree
2334
+ sage: LBT([LBT([],label=1),LBT([],label=4)],label=2).labels()
2335
+ [2, 1, 4]
2336
+ """
2337
+ return [t.label() for t in self.subtrees()]
2338
+
2339
+ def leaf_labels(self):
2340
+ """
2341
+ Return the list of labels of the leaves of ``self``.
2342
+
2343
+ In case of a labelled binary tree, these "leaves" are not actually
2344
+ the leaves of the binary trees, but the nodes whose both children
2345
+ are leaves!
2346
+
2347
+ EXAMPLES::
2348
+
2349
+ sage: LT = LabelledOrderedTree
2350
+ sage: t = LT([LT([],label='b'),LT([],label='c')],label='a')
2351
+ sage: t.leaf_labels()
2352
+ ['b', 'c']
2353
+
2354
+ sage: LBT = LabelledBinaryTree
2355
+ sage: bt = LBT([LBT([],label='b'),LBT([],label='c')],label='a')
2356
+ sage: bt.leaf_labels()
2357
+ ['b', 'c']
2358
+ sage: LBT([], label='1').leaf_labels()
2359
+ ['1']
2360
+ sage: LBT(None).leaf_labels()
2361
+ []
2362
+ """
2363
+ return [t.label() for t in self.subtrees() if t.node_number() == 1]
2364
+
2365
+ def __eq__(self, other):
2366
+ """
2367
+ Test if ``self`` is equal to ``other``.
2368
+
2369
+ TESTS::
2370
+
2371
+ sage LabelledOrderedTree() == LabelledOrderedTree()
2372
+ True
2373
+ sage LabelledOrderedTree([]) == LabelledOrderedTree()
2374
+ False
2375
+ sage: t1 = LabelledOrderedTree([[],[[]]])
2376
+ sage: t2 = LabelledOrderedTree([[],[[]]])
2377
+ sage: t1 == t2
2378
+ True
2379
+ sage: t2 = LabelledOrderedTree(t1)
2380
+ sage: t1 == t2
2381
+ True
2382
+ sage: t1 = LabelledOrderedTree([[],[[]]])
2383
+ sage: t2 = LabelledOrderedTree([[[]],[]])
2384
+ sage: t1 == t2
2385
+ False
2386
+ """
2387
+ return super().__eq__(other) and self._label == other._label
2388
+
2389
+ def _hash_(self):
2390
+ """
2391
+ Return the hash value for ``self``.
2392
+
2393
+ TESTS::
2394
+
2395
+ sage: t1 = LabelledOrderedTree([[],[[]]], label = 1); t1hash = t1.__hash__()
2396
+ sage: LabelledOrderedTree([[],[[]]], label = 1).__hash__() == t1hash
2397
+ True
2398
+ sage: LabelledOrderedTree([[[]],[]], label = 1).__hash__() == t1hash
2399
+ False
2400
+ sage: LabelledOrderedTree(t1, label = 1).__hash__() == t1hash
2401
+ True
2402
+ sage: LabelledOrderedTree([[],[[]]], label = 25).__hash__() == t1hash
2403
+ False
2404
+ sage: LabelledOrderedTree(t1, label = 25).__hash__() == t1hash
2405
+ False
2406
+
2407
+ sage: LabelledBinaryTree([[],[[],[]]], label = 25).__hash__() #random
2408
+ 8544617749928727644
2409
+
2410
+ We check that the hash value depends on the value of the labels of the
2411
+ subtrees::
2412
+
2413
+ sage: LBT = LabelledBinaryTree
2414
+ sage: t1 = LBT([], label = 1)
2415
+ sage: t2 = LBT([], label = 2)
2416
+ sage: t3 = LBT([], label = 3)
2417
+ sage: t12 = LBT([t1, t2], label = "a")
2418
+ sage: t13 = LBT([t1, t3], label = "a")
2419
+ sage: t12.__hash__() != t13.__hash__()
2420
+ True
2421
+ """
2422
+ return self._UnLabelled._hash_(self) ^ hash(self._label)
2423
+
2424
+ def shape(self):
2425
+ """
2426
+ Return the unlabelled tree associated to ``self``.
2427
+
2428
+ EXAMPLES::
2429
+
2430
+ sage: t = LabelledOrderedTree([[],[[]]], label = 25).shape(); t
2431
+ [[], [[]]]
2432
+
2433
+ sage: LabelledBinaryTree([[],[[],[]]], label = 25).shape()
2434
+ [[., .], [[., .], [., .]]]
2435
+
2436
+ sage: LRT = LabelledRootedTree
2437
+ sage: tb = LRT([],label='b')
2438
+ sage: LRT([tb, tb], label='a').shape()
2439
+ [[], []]
2440
+
2441
+ TESTS::
2442
+
2443
+ sage: t.parent()
2444
+ Ordered trees
2445
+ sage: type(t)
2446
+ <class 'sage.combinat.ordered_tree.OrderedTrees_all_with_category.element_class'>
2447
+ """
2448
+ TR = self.parent().unlabelled_trees()
2449
+ if not self:
2450
+ return TR.leaf()
2451
+ else:
2452
+ return TR._element_constructor_([i.shape() for i in self])
2453
+
2454
+ def as_digraph(self):
2455
+ """
2456
+ Return a directed graph version of ``self``.
2457
+
2458
+ .. WARNING::
2459
+
2460
+ At this time, the output makes sense only if ``self`` is a
2461
+ labelled binary tree with no repeated labels and no ``None``
2462
+ labels.
2463
+
2464
+ EXAMPLES::
2465
+
2466
+ sage: LT = LabelledOrderedTrees()
2467
+ sage: t1 = LT([LT([],label=6),LT([],label=1)],label=9)
2468
+ sage: t1.as_digraph()
2469
+ Digraph on 3 vertices
2470
+
2471
+ sage: t = BinaryTree([[None, None],[[],None]])
2472
+ sage: lt = t.canonical_labelling()
2473
+ sage: lt.as_digraph()
2474
+ Digraph on 4 vertices
2475
+ """
2476
+ from sage.graphs.digraph import DiGraph
2477
+ resu = {self.label():
2478
+ [t.label() for t in self if not t.is_empty()]}
2479
+ resu = DiGraph(resu, format='dict_of_lists')
2480
+ for t in self:
2481
+ if not t.is_empty():
2482
+ resu = resu.union(t.as_digraph())
2483
+ return resu
2484
+
2485
+
2486
+ class AbstractLabelledClonableTree(AbstractLabelledTree,
2487
+ AbstractClonableTree):
2488
+ """
2489
+ Abstract Labelled Clonable Tree.
2490
+
2491
+ This class takes care of modification for the label by the clone protocol.
2492
+
2493
+ .. NOTE:: Due to the limitation of Cython inheritance, one cannot inherit
2494
+ here from :class:`~sage.structure.list_clone.ClonableArray`, because it would prevent us to
2495
+ inherit later from :class:`~sage.structure.list_clone.ClonableList`.
2496
+ """
2497
+
2498
+ def set_root_label(self, label):
2499
+ """
2500
+ Set the label of the root of ``self``.
2501
+
2502
+ INPUT:
2503
+
2504
+ - ``label`` -- any Sage object
2505
+
2506
+ OUTPUT: none, ``self`` is modified in place
2507
+
2508
+ .. NOTE::
2509
+
2510
+ ``self`` must be in a mutable state. See
2511
+ :mod:`sage.structure.list_clone` for more details about
2512
+ mutability.
2513
+
2514
+ EXAMPLES::
2515
+
2516
+ sage: t = LabelledOrderedTree([[],[[],[]]])
2517
+ sage: t.set_root_label(3)
2518
+ Traceback (most recent call last):
2519
+ ...
2520
+ ValueError: object is immutable; please change a copy instead.
2521
+ sage: with t.clone() as t:
2522
+ ....: t.set_root_label(3)
2523
+ sage: t.label()
2524
+ 3
2525
+ sage: t
2526
+ 3[None[], None[None[], None[]]]
2527
+
2528
+ This also works for binary trees::
2529
+
2530
+ sage: bt = LabelledBinaryTree([[],[]])
2531
+ sage: bt.set_root_label(3)
2532
+ Traceback (most recent call last):
2533
+ ...
2534
+ ValueError: object is immutable; please change a copy instead.
2535
+ sage: with bt.clone() as bt:
2536
+ ....: bt.set_root_label(3)
2537
+ sage: bt.label()
2538
+ 3
2539
+ sage: bt
2540
+ 3[None[., .], None[., .]]
2541
+
2542
+ TESTS::
2543
+
2544
+ sage: with t.clone() as t:
2545
+ ....: t[0] = LabelledOrderedTree(t[0], label = 4)
2546
+ sage: t
2547
+ 3[4[], None[None[], None[]]]
2548
+ sage: with t.clone() as t:
2549
+ ....: t[1,0] = LabelledOrderedTree(t[1,0], label = 42)
2550
+ sage: t
2551
+ 3[4[], None[42[], None[]]]
2552
+ """
2553
+ self._require_mutable()
2554
+ self._label = label
2555
+
2556
+ def set_label(self, path, label):
2557
+ """
2558
+ Change the label of subtree indexed by ``path`` to ``label``.
2559
+
2560
+ INPUT:
2561
+
2562
+ - ``path`` -- ``None`` (default) or a path (list or tuple of children
2563
+ index in the tree)
2564
+
2565
+ - ``label`` -- any sage object
2566
+
2567
+ OUTPUT: nothing, ``self`` is modified in place
2568
+
2569
+ .. NOTE::
2570
+
2571
+ ``self`` must be in a mutable state. See
2572
+ :mod:`sage.structure.list_clone` for more details about
2573
+ mutability.
2574
+
2575
+ EXAMPLES::
2576
+
2577
+ sage: t = LabelledOrderedTree([[],[[],[]]])
2578
+ sage: t.set_label((0,), 4)
2579
+ Traceback (most recent call last):
2580
+ ...
2581
+ ValueError: object is immutable; please change a copy instead.
2582
+ sage: with t.clone() as t:
2583
+ ....: t.set_label((0,), 4)
2584
+ sage: t
2585
+ None[4[], None[None[], None[]]]
2586
+ sage: with t.clone() as t:
2587
+ ....: t.set_label((1,0), label = 42)
2588
+ sage: t
2589
+ None[4[], None[42[], None[]]]
2590
+
2591
+ .. TODO::
2592
+
2593
+ Do we want to implement the following syntactic sugar::
2594
+
2595
+ with t.clone() as tt:
2596
+ tt.labels[1,2] = 3 ?
2597
+ """
2598
+ self._require_mutable()
2599
+ path = tuple(path)
2600
+ if path == ():
2601
+ self._label = label
2602
+ else:
2603
+ with self[path[0]].clone() as child:
2604
+ child.set_label(path[1:], label)
2605
+ self[path[0]] = child
2606
+
2607
+ def map_labels(self, f):
2608
+ """
2609
+ Apply the function `f` to the labels of ``self``.
2610
+
2611
+ This method returns a copy of ``self`` on which the function `f` has
2612
+ been applied on all labels (a label `x` is replaced by `f(x)`).
2613
+
2614
+ EXAMPLES::
2615
+
2616
+ sage: LT = LabelledOrderedTree
2617
+ sage: t = LT([LT([],label=1),LT([],label=7)],label=3); t
2618
+ 3[1[], 7[]]
2619
+ sage: t.map_labels(lambda z:z+1)
2620
+ 4[2[], 8[]]
2621
+
2622
+ sage: LBT = LabelledBinaryTree
2623
+ sage: bt = LBT([LBT([],label=1),LBT([],label=4)],label=2); bt
2624
+ 2[1[., .], 4[., .]]
2625
+ sage: bt.map_labels(lambda z:z+1)
2626
+ 3[2[., .], 5[., .]]
2627
+ """
2628
+ if self.is_empty():
2629
+ return self
2630
+ return self.parent()([t.map_labels(f) for t in self],
2631
+ label=f(self.label()))
2632
+
2633
+
2634
+ def from_hexacode(ch, parent=None, label='@'):
2635
+ r"""
2636
+ Transform a hexadecimal string into a tree.
2637
+
2638
+ INPUT:
2639
+
2640
+ - ``ch`` -- a hexadecimal string
2641
+
2642
+ - ``parent`` -- kind of trees to be produced. If ``None``, this will
2643
+ be ``LabelledOrderedTrees``
2644
+
2645
+ - ``label`` -- a label (default: ``'@'``) to be used for every vertex
2646
+ of the tree
2647
+
2648
+ See :meth:`AbstractTree.to_hexacode` for the description of the encoding
2649
+
2650
+ See :func:`_from_hexacode_aux` for the actual code
2651
+
2652
+ EXAMPLES::
2653
+
2654
+ sage: from sage.combinat.abstract_tree import from_hexacode
2655
+ sage: from_hexacode('12000', LabelledOrderedTrees())
2656
+ @[@[@[], @[]]]
2657
+ sage: from_hexacode('12000')
2658
+ @[@[@[], @[]]]
2659
+
2660
+ sage: from_hexacode('1200', LabelledOrderedTrees())
2661
+ @[@[@[], @[]]]
2662
+
2663
+ It can happen that only a prefix of the word is used::
2664
+
2665
+ sage: from_hexacode('a'+14*'0', LabelledOrderedTrees())
2666
+ @[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]]
2667
+
2668
+ One can choose the label::
2669
+
2670
+ sage: from_hexacode('1200', LabelledOrderedTrees(), label='o')
2671
+ o[o[o[], o[]]]
2672
+
2673
+ One can also create other kinds of trees::
2674
+
2675
+ sage: from_hexacode('1200', OrderedTrees())
2676
+ [[[], []]]
2677
+ """
2678
+ if parent is None:
2679
+ from sage.combinat.ordered_tree import LabelledOrderedTrees
2680
+ parent = LabelledOrderedTrees()
2681
+ return _from_hexacode_aux(ch, parent, label)[0]
2682
+
2683
+
2684
+ def _from_hexacode_aux(ch, parent, label='@'):
2685
+ r"""
2686
+ Transform a hexadecimal string into a tree and a remainder string.
2687
+
2688
+ INPUT:
2689
+
2690
+ - ``ch`` -- a hexadecimal string
2691
+
2692
+ - ``parent`` -- kind of trees to be produced
2693
+
2694
+ - ``label`` -- a label (default: ``'@'``) to be used for every vertex
2695
+ of the tree
2696
+
2697
+ This method is used in :func:`from_hexacode`
2698
+
2699
+ EXAMPLES::
2700
+
2701
+ sage: from sage.combinat.abstract_tree import _from_hexacode_aux
2702
+ sage: _from_hexacode_aux('12000', LabelledOrderedTrees())
2703
+ (@[@[@[], @[]]], '0')
2704
+
2705
+ sage: _from_hexacode_aux('1200', LabelledOrderedTrees())
2706
+ (@[@[@[], @[]]], '')
2707
+
2708
+ sage: _from_hexacode_aux('1200', OrderedTrees())
2709
+ ([[[], []]], '')
2710
+
2711
+ sage: _from_hexacode_aux('a00000000000000', LabelledOrderedTrees())
2712
+ (@[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]], '0000')
2713
+ """
2714
+ Trees = parent
2715
+ width = int(ch[0], 16) # hexadecimal input
2716
+ remainder = ch[1:]
2717
+ if width == 0:
2718
+ return (Trees([], label), remainder)
2719
+ branches = {}
2720
+ for i in range(width):
2721
+ tree, remainder = _from_hexacode_aux(remainder, parent, label)
2722
+ branches[i] = tree
2723
+ return (Trees(branches.values(), label), remainder)