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