passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1446 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
"""
|
3
|
+
Ordered rooted trees
|
4
|
+
|
5
|
+
AUTHORS:
|
6
|
+
|
7
|
+
- Florent Hivert (2010-2011): initial revision
|
8
|
+
- Frédéric Chapoton (2010): contributed some methods
|
9
|
+
"""
|
10
|
+
# ****************************************************************************
|
11
|
+
# Copyright (C) 2010 Florent Hivert <Florent.Hivert@univ-rouen.fr>,
|
12
|
+
#
|
13
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
14
|
+
# as published by the Free Software Foundation; either version 2 of
|
15
|
+
# the License, or (at your option) any later version.
|
16
|
+
# https://www.gnu.org/licenses/
|
17
|
+
# ****************************************************************************
|
18
|
+
|
19
|
+
import itertools
|
20
|
+
|
21
|
+
from sage.structure.list_clone import ClonableArray, ClonableList
|
22
|
+
from sage.structure.parent import Parent
|
23
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
24
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
25
|
+
from sage.misc.lazy_attribute import lazy_class_attribute
|
26
|
+
from sage.misc.lazy_import import lazy_import
|
27
|
+
from sage.combinat.abstract_tree import (AbstractClonableTree,
|
28
|
+
AbstractLabelledClonableTree)
|
29
|
+
from sage.combinat.combinatorial_map import combinatorial_map
|
30
|
+
from sage.misc.cachefunc import cached_method
|
31
|
+
from sage.categories.sets_cat import Sets, EmptySetError
|
32
|
+
from sage.rings.integer import Integer
|
33
|
+
from sage.sets.non_negative_integers import NonNegativeIntegers
|
34
|
+
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
|
35
|
+
from sage.sets.family import Family
|
36
|
+
from sage.rings.infinity import Infinity
|
37
|
+
|
38
|
+
lazy_import('sage.combinat.dyck_word', 'CompleteDyckWords_size')
|
39
|
+
|
40
|
+
|
41
|
+
class OrderedTree(AbstractClonableTree, ClonableList,
|
42
|
+
metaclass=InheritComparisonClasscallMetaclass):
|
43
|
+
"""
|
44
|
+
The class of (ordered rooted) trees.
|
45
|
+
|
46
|
+
An ordered tree is constructed from a node, called the root, on which one
|
47
|
+
has grafted a possibly empty list of trees. There is a total order on the
|
48
|
+
children of a node which is given by the order of the elements in the
|
49
|
+
list. Note that there is no empty ordered tree (so the smallest ordered
|
50
|
+
tree consists of just one node).
|
51
|
+
|
52
|
+
INPUT:
|
53
|
+
|
54
|
+
One can create a tree from any list (or more generally iterable) of trees
|
55
|
+
or objects convertible to a tree. Alternatively a string is also
|
56
|
+
accepted. The syntax is the same as for printing: children are grouped by
|
57
|
+
square brackets.
|
58
|
+
|
59
|
+
EXAMPLES::
|
60
|
+
|
61
|
+
sage: x = OrderedTree([])
|
62
|
+
sage: x1 = OrderedTree([x,x])
|
63
|
+
sage: x2 = OrderedTree([[],[]])
|
64
|
+
sage: x1 == x2
|
65
|
+
True
|
66
|
+
sage: tt1 = OrderedTree([x,x1,x2])
|
67
|
+
sage: tt2 = OrderedTree([[], [[], []], x2])
|
68
|
+
sage: tt1 == tt2
|
69
|
+
True
|
70
|
+
|
71
|
+
sage: OrderedTree([]) == OrderedTree()
|
72
|
+
True
|
73
|
+
|
74
|
+
TESTS::
|
75
|
+
|
76
|
+
sage: x1.__hash__() == x2.__hash__()
|
77
|
+
True
|
78
|
+
sage: tt1.__hash__() == tt2.__hash__()
|
79
|
+
True
|
80
|
+
|
81
|
+
Trees are usually immutable. However they inherit from
|
82
|
+
:class:`sage.structure.list_clone.ClonableList`, so that they can be
|
83
|
+
modified using the clone protocol. Let us now see what this means.
|
84
|
+
|
85
|
+
Trying to modify a non-mutable tree raises an error::
|
86
|
+
|
87
|
+
sage: tt1[1] = tt2
|
88
|
+
Traceback (most recent call last):
|
89
|
+
...
|
90
|
+
ValueError: object is immutable; please change a copy instead.
|
91
|
+
|
92
|
+
Here is the correct way to do it::
|
93
|
+
|
94
|
+
sage: with tt2.clone() as tt2:
|
95
|
+
....: tt2[1] = tt1
|
96
|
+
sage: tt2
|
97
|
+
[[], [[], [[], []], [[], []]], [[], []]]
|
98
|
+
|
99
|
+
It is also possible to append a child to a tree::
|
100
|
+
|
101
|
+
sage: with tt2.clone() as tt3:
|
102
|
+
....: tt3.append(OrderedTree([]))
|
103
|
+
sage: tt3
|
104
|
+
[[], [[], [[], []], [[], []]], [[], []], []]
|
105
|
+
|
106
|
+
Or to insert a child in a tree::
|
107
|
+
|
108
|
+
sage: with tt2.clone() as tt3:
|
109
|
+
....: tt3.insert(2, OrderedTree([]))
|
110
|
+
sage: tt3
|
111
|
+
[[], [[], [[], []], [[], []]], [], [[], []]]
|
112
|
+
|
113
|
+
We check that ``tt1`` is not modified and that everything is correct with
|
114
|
+
respect to equality::
|
115
|
+
|
116
|
+
sage: tt1
|
117
|
+
[[], [[], []], [[], []]]
|
118
|
+
sage: tt1 == tt2
|
119
|
+
False
|
120
|
+
sage: tt1.__hash__() == tt2.__hash__()
|
121
|
+
False
|
122
|
+
|
123
|
+
TESTS::
|
124
|
+
|
125
|
+
sage: tt1bis = OrderedTree(tt1)
|
126
|
+
sage: with tt1.clone() as tt1:
|
127
|
+
....: tt1[1] = tt1bis
|
128
|
+
sage: tt1
|
129
|
+
[[], [[], [[], []], [[], []]], [[], []]]
|
130
|
+
sage: tt1 == tt2
|
131
|
+
True
|
132
|
+
sage: tt1.__hash__() == tt2.__hash__()
|
133
|
+
True
|
134
|
+
sage: len(tt1)
|
135
|
+
3
|
136
|
+
sage: tt1[2]
|
137
|
+
[[], []]
|
138
|
+
sage: tt1[3]
|
139
|
+
Traceback (most recent call last):
|
140
|
+
...
|
141
|
+
IndexError: list index out of range
|
142
|
+
sage: tt1[1:2]
|
143
|
+
[[[], [[], []], [[], []]]]
|
144
|
+
|
145
|
+
Various tests involving construction, equality and hashing::
|
146
|
+
|
147
|
+
sage: OrderedTree() == OrderedTree()
|
148
|
+
True
|
149
|
+
sage: t1 = OrderedTree([[],[[]]])
|
150
|
+
sage: t2 = OrderedTree([[],[[]]])
|
151
|
+
sage: t1 == t2
|
152
|
+
True
|
153
|
+
sage: t2 = OrderedTree(t1)
|
154
|
+
sage: t1 == t2
|
155
|
+
True
|
156
|
+
sage: t1 = OrderedTree([[],[[]]])
|
157
|
+
sage: t2 = OrderedTree([[[]],[]])
|
158
|
+
sage: t1 == t2
|
159
|
+
False
|
160
|
+
|
161
|
+
sage: t1 = OrderedTree([[],[[]]])
|
162
|
+
sage: t2 = OrderedTree([[],[[]]])
|
163
|
+
sage: t1.__hash__() == t2.__hash__()
|
164
|
+
True
|
165
|
+
sage: t2 = OrderedTree([[[]],[]])
|
166
|
+
sage: t1.__hash__() == t2.__hash__()
|
167
|
+
False
|
168
|
+
sage: OrderedTree().__hash__() == OrderedTree([]).__hash__()
|
169
|
+
True
|
170
|
+
sage: tt1 = OrderedTree([t1,t2,t1])
|
171
|
+
sage: tt2 = OrderedTree([t1, [[[]],[]], t1])
|
172
|
+
sage: tt1.__hash__() == tt2.__hash__()
|
173
|
+
True
|
174
|
+
|
175
|
+
Check that the hash value is correctly updated after modification::
|
176
|
+
|
177
|
+
sage: with tt2.clone() as tt2:
|
178
|
+
....: tt2[1,1] = tt1
|
179
|
+
sage: tt1.__hash__() == tt2.__hash__()
|
180
|
+
False
|
181
|
+
"""
|
182
|
+
@staticmethod
|
183
|
+
def __classcall_private__(cls, *args, **opts):
|
184
|
+
"""
|
185
|
+
Ensure that trees created by the enumerated sets and directly
|
186
|
+
are the same and that they are instances of :class:`OrderedTree`
|
187
|
+
|
188
|
+
TESTS::
|
189
|
+
|
190
|
+
sage: issubclass(OrderedTrees().element_class, OrderedTree)
|
191
|
+
True
|
192
|
+
sage: t0 = OrderedTree([[],[[], []]])
|
193
|
+
sage: t0.parent()
|
194
|
+
Ordered trees
|
195
|
+
sage: type(t0)
|
196
|
+
<class 'sage.combinat.ordered_tree.OrderedTrees_all_with_category.element_class'>
|
197
|
+
|
198
|
+
sage: t1 = OrderedTrees()([[],[[], []]])
|
199
|
+
sage: t1.parent() is t0.parent()
|
200
|
+
True
|
201
|
+
sage: type(t1) is type(t0)
|
202
|
+
True
|
203
|
+
|
204
|
+
sage: t1 = OrderedTrees(4)([[],[[]]])
|
205
|
+
sage: t1.parent() is t0.parent()
|
206
|
+
True
|
207
|
+
sage: type(t1) is type(t0)
|
208
|
+
True
|
209
|
+
"""
|
210
|
+
return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
|
211
|
+
|
212
|
+
@lazy_class_attribute
|
213
|
+
def _auto_parent(cls):
|
214
|
+
"""
|
215
|
+
The automatic parent of the elements of this class.
|
216
|
+
|
217
|
+
When calling the constructor of an element of this class, one needs a
|
218
|
+
parent. This class attribute specifies which parent is used.
|
219
|
+
|
220
|
+
EXAMPLES::
|
221
|
+
|
222
|
+
sage: OrderedTree([[],[[]]])._auto_parent
|
223
|
+
Ordered trees
|
224
|
+
sage: OrderedTree([[],[[]]]).parent()
|
225
|
+
Ordered trees
|
226
|
+
|
227
|
+
.. NOTE::
|
228
|
+
|
229
|
+
It is possible to bypass the automatic parent mechanism using::
|
230
|
+
|
231
|
+
sage: t1 = OrderedTree.__new__(OrderedTree, Parent(), [])
|
232
|
+
sage: t1.__init__(Parent(), [])
|
233
|
+
sage: t1
|
234
|
+
[]
|
235
|
+
sage: t1.parent()
|
236
|
+
<sage.structure.parent.Parent object at ...>
|
237
|
+
"""
|
238
|
+
return OrderedTrees_all()
|
239
|
+
|
240
|
+
def __init__(self, parent=None, children=None, check=True):
|
241
|
+
"""
|
242
|
+
TESTS::
|
243
|
+
|
244
|
+
sage: t1 = OrderedTrees(4)([[],[[]]])
|
245
|
+
sage: TestSuite(t1).run()
|
246
|
+
sage: OrderedTrees()("[]") # indirect doctest
|
247
|
+
[]
|
248
|
+
sage: all(OrderedTree(repr(tr)) == tr for i in range(6) for tr in OrderedTrees(i))
|
249
|
+
True
|
250
|
+
"""
|
251
|
+
if children is None:
|
252
|
+
children = []
|
253
|
+
if isinstance(children, str):
|
254
|
+
children = eval(children)
|
255
|
+
if (children.__class__ is self.__class__ and
|
256
|
+
children.parent() == parent):
|
257
|
+
children = list(children)
|
258
|
+
else:
|
259
|
+
children = [self.__class__(parent, x) for x in children]
|
260
|
+
ClonableArray.__init__(self, parent, children, check=check)
|
261
|
+
|
262
|
+
def is_empty(self):
|
263
|
+
"""
|
264
|
+
Return if ``self`` is the empty tree.
|
265
|
+
|
266
|
+
For ordered trees, this always returns ``False``.
|
267
|
+
|
268
|
+
.. NOTE:: this is different from ``bool(t)`` which returns whether
|
269
|
+
``t`` has some child or not.
|
270
|
+
|
271
|
+
EXAMPLES::
|
272
|
+
|
273
|
+
sage: t = OrderedTrees(4)([[],[[]]])
|
274
|
+
sage: t.is_empty()
|
275
|
+
False
|
276
|
+
sage: bool(t)
|
277
|
+
True
|
278
|
+
"""
|
279
|
+
return False
|
280
|
+
|
281
|
+
def _to_binary_tree_rec(self, bijection='left'):
|
282
|
+
r"""
|
283
|
+
Internal recursive method to obtain a binary tree from an ordered
|
284
|
+
tree.
|
285
|
+
|
286
|
+
See :meth:`to_binary_tree_left_branch` and
|
287
|
+
:meth:`to_binary_tree_right_branch` for what it does.
|
288
|
+
|
289
|
+
EXAMPLES::
|
290
|
+
|
291
|
+
sage: T = OrderedTree([[],[]])
|
292
|
+
sage: T._to_binary_tree_rec()
|
293
|
+
[[., .], .]
|
294
|
+
sage: T._to_binary_tree_rec(bijection='right')
|
295
|
+
[., [., .]]
|
296
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
297
|
+
sage: T._to_binary_tree_rec()
|
298
|
+
[[[., .], [[., .], .]], [[., .], [., .]]]
|
299
|
+
sage: T._to_binary_tree_rec(bijection='right')
|
300
|
+
[., [[., [., .]], [[., [[., .], .]], .]]]
|
301
|
+
"""
|
302
|
+
from sage.combinat.binary_tree import BinaryTree
|
303
|
+
root = BinaryTree()
|
304
|
+
if bijection == "left":
|
305
|
+
for child in self:
|
306
|
+
root = BinaryTree([root, child._to_binary_tree_rec(bijection)])
|
307
|
+
elif bijection == "right":
|
308
|
+
children = list(self)
|
309
|
+
children.reverse()
|
310
|
+
for child in children:
|
311
|
+
root = BinaryTree([child._to_binary_tree_rec(bijection), root])
|
312
|
+
else:
|
313
|
+
raise ValueError("the bijection argument should be either "
|
314
|
+
"left or right")
|
315
|
+
return root
|
316
|
+
|
317
|
+
@combinatorial_map(name="To binary tree, left brother = left child")
|
318
|
+
def to_binary_tree_left_branch(self):
|
319
|
+
r"""
|
320
|
+
Return a binary tree of size `n-1` (where `n` is the size of `t`,
|
321
|
+
and where `t` is ``self``) obtained from `t` by the following
|
322
|
+
recursive rule:
|
323
|
+
|
324
|
+
- if `x` is the left brother of `y` in `t`, then `x` becomes the
|
325
|
+
left child of `y`;
|
326
|
+
- if `x` is the last child of `y` in `t`, then `x` becomes the
|
327
|
+
right child of `y`,
|
328
|
+
|
329
|
+
and removing the root of `t`.
|
330
|
+
|
331
|
+
EXAMPLES::
|
332
|
+
|
333
|
+
sage: T = OrderedTree([[],[]])
|
334
|
+
sage: T.to_binary_tree_left_branch()
|
335
|
+
[[., .], .]
|
336
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
337
|
+
sage: T.to_binary_tree_left_branch()
|
338
|
+
[[[., .], [[., .], .]], [[., .], [., .]]]
|
339
|
+
|
340
|
+
TESTS::
|
341
|
+
|
342
|
+
sage: T = OrderedTree([[],[]])
|
343
|
+
sage: T == T.to_binary_tree_left_branch().to_ordered_tree_left_branch()
|
344
|
+
True
|
345
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
346
|
+
sage: T == T.to_binary_tree_left_branch().to_ordered_tree_left_branch()
|
347
|
+
True
|
348
|
+
"""
|
349
|
+
return self._to_binary_tree_rec()
|
350
|
+
|
351
|
+
@combinatorial_map(name="To parallelogram polyomino")
|
352
|
+
def to_parallelogram_polyomino(self, bijection=None):
|
353
|
+
r"""
|
354
|
+
Return a polyomino parallelogram.
|
355
|
+
|
356
|
+
INPUT:
|
357
|
+
|
358
|
+
- ``bijection`` -- (default: ``'Boussicault-Socci'``) is the name of the
|
359
|
+
bijection to use. Possible values are ``'Boussicault-Socci'``,
|
360
|
+
``'via dyck and Delest-Viennot'``.
|
361
|
+
|
362
|
+
EXAMPLES::
|
363
|
+
|
364
|
+
sage: # needs sage.combinat sage.modules
|
365
|
+
sage: T = OrderedTree([[[], [[], [[]]]], [], [[[],[]]], [], []])
|
366
|
+
sage: T.to_parallelogram_polyomino(bijection='Boussicault-Socci')
|
367
|
+
[[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
|
368
|
+
[1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0]]
|
369
|
+
sage: T = OrderedTree( [] )
|
370
|
+
sage: T.to_parallelogram_polyomino()
|
371
|
+
[[1], [1]]
|
372
|
+
sage: T = OrderedTree( [[]] )
|
373
|
+
sage: T.to_parallelogram_polyomino()
|
374
|
+
[[0, 1], [1, 0]]
|
375
|
+
sage: T = OrderedTree( [[],[]] )
|
376
|
+
sage: T.to_parallelogram_polyomino()
|
377
|
+
[[0, 1, 1], [1, 1, 0]]
|
378
|
+
sage: T = OrderedTree( [[[]]] )
|
379
|
+
sage: T.to_parallelogram_polyomino()
|
380
|
+
[[0, 0, 1], [1, 0, 0]]
|
381
|
+
"""
|
382
|
+
if (bijection is None) or (bijection == 'Boussicault-Socci'):
|
383
|
+
return self._to_parallelogram_polyomino_Boussicault_Socci()
|
384
|
+
if bijection == 'via dyck and Delest-Viennot':
|
385
|
+
raise NotImplementedError
|
386
|
+
raise ValueError('unknown bijection')
|
387
|
+
|
388
|
+
def _to_parallelogram_polyomino_Boussicault_Socci(self):
|
389
|
+
r"""
|
390
|
+
Return the polyomino parallelogram using the Boussicault-Socci
|
391
|
+
bijection.
|
392
|
+
|
393
|
+
EXAMPLES::
|
394
|
+
|
395
|
+
sage: # needs sage.combinat sage.modules
|
396
|
+
sage: T = OrderedTree(
|
397
|
+
....: [[[], [[], [[]]]], [], [[[],[]]], [], []]
|
398
|
+
....: )
|
399
|
+
sage: T._to_parallelogram_polyomino_Boussicault_Socci()
|
400
|
+
[[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0]]
|
401
|
+
sage: T = OrderedTree( [] )
|
402
|
+
sage: T._to_parallelogram_polyomino_Boussicault_Socci()
|
403
|
+
[[1], [1]]
|
404
|
+
sage: T = OrderedTree( [[]] )
|
405
|
+
sage: T._to_parallelogram_polyomino_Boussicault_Socci()
|
406
|
+
[[0, 1], [1, 0]]
|
407
|
+
sage: T = OrderedTree( [[],[]] )
|
408
|
+
sage: T._to_parallelogram_polyomino_Boussicault_Socci()
|
409
|
+
[[0, 1, 1], [1, 1, 0]]
|
410
|
+
sage: T = OrderedTree( [[[]]] )
|
411
|
+
sage: T._to_parallelogram_polyomino_Boussicault_Socci()
|
412
|
+
[[0, 0, 1], [1, 0, 0]]
|
413
|
+
"""
|
414
|
+
from sage.combinat.parallelogram_polyomino import ParallelogramPolyomino
|
415
|
+
if self.node_number() == 1:
|
416
|
+
return ParallelogramPolyomino([[1], [1]])
|
417
|
+
upper_nodes = []
|
418
|
+
lower_nodes = []
|
419
|
+
w_coordinate = {}
|
420
|
+
w_coordinate[()] = 0
|
421
|
+
h_coordinate = {}
|
422
|
+
|
423
|
+
cpt = 0
|
424
|
+
for h in range(0, self.depth(), 2):
|
425
|
+
for node in self.paths_at_depth(h):
|
426
|
+
h_coordinate[node] = cpt
|
427
|
+
lower_nodes.append(node)
|
428
|
+
cpt += 1
|
429
|
+
|
430
|
+
cpt = 0
|
431
|
+
for h in range(1, self.depth(), 2):
|
432
|
+
for node in self.paths_at_depth(h):
|
433
|
+
w_coordinate[node] = cpt
|
434
|
+
upper_nodes.append(node)
|
435
|
+
cpt += 1
|
436
|
+
|
437
|
+
def W(path):
|
438
|
+
if path in w_coordinate:
|
439
|
+
return w_coordinate[path]
|
440
|
+
else:
|
441
|
+
return w_coordinate[path[:-1]]
|
442
|
+
|
443
|
+
def H(path):
|
444
|
+
if path in h_coordinate:
|
445
|
+
return h_coordinate[path]
|
446
|
+
else:
|
447
|
+
return h_coordinate[path[:-1]]
|
448
|
+
|
449
|
+
lower_path = []
|
450
|
+
for i in range(1, len(lower_nodes)):
|
451
|
+
lower_path.append(0)
|
452
|
+
lower_path += [1] * (W(lower_nodes[i]) - W(lower_nodes[i - 1]))
|
453
|
+
lower_path.append(0)
|
454
|
+
lower_path += [1] * (self.node_number() - len(lower_path))
|
455
|
+
|
456
|
+
upper_path = []
|
457
|
+
for i in range(1, len(upper_nodes)):
|
458
|
+
upper_path.append(1)
|
459
|
+
upper_path += [0] * (H(upper_nodes[i]) - H(upper_nodes[i - 1]))
|
460
|
+
upper_path.append(1)
|
461
|
+
upper_path += [0] * (self.node_number() - len(upper_path))
|
462
|
+
|
463
|
+
return ParallelogramPolyomino([lower_path, upper_path])
|
464
|
+
|
465
|
+
@combinatorial_map(name="To binary tree, right brother = right child")
|
466
|
+
def to_binary_tree_right_branch(self):
|
467
|
+
r"""
|
468
|
+
Return a binary tree of size `n-1` (where `n` is the size of `t`,
|
469
|
+
and where `t` is ``self``) obtained from `t` by the following
|
470
|
+
recursive rule:
|
471
|
+
|
472
|
+
- if `x` is the right brother of `y` in `t`, then`x` becomes the
|
473
|
+
right child of `y`;
|
474
|
+
- if `x` is the first child of `y` in `t`, then `x` becomes the
|
475
|
+
left child of `y`,
|
476
|
+
|
477
|
+
and removing the root of `t`.
|
478
|
+
|
479
|
+
EXAMPLES::
|
480
|
+
|
481
|
+
sage: T = OrderedTree([[],[]])
|
482
|
+
sage: T.to_binary_tree_right_branch()
|
483
|
+
[., [., .]]
|
484
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
485
|
+
sage: T.to_binary_tree_right_branch()
|
486
|
+
[., [[., [., .]], [[., [[., .], .]], .]]]
|
487
|
+
|
488
|
+
TESTS::
|
489
|
+
|
490
|
+
sage: T = OrderedTree([[],[]])
|
491
|
+
sage: T == T.to_binary_tree_right_branch().to_ordered_tree_right_branch()
|
492
|
+
True
|
493
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
494
|
+
sage: T == T.to_binary_tree_right_branch().to_ordered_tree_right_branch()
|
495
|
+
True
|
496
|
+
"""
|
497
|
+
return self._to_binary_tree_rec(bijection='right')
|
498
|
+
|
499
|
+
@combinatorial_map(name="To Dyck path")
|
500
|
+
def to_dyck_word(self):
|
501
|
+
r"""
|
502
|
+
Return the Dyck path corresponding to ``self`` where the maximal
|
503
|
+
height of the Dyck path is the depth of ``self`` .
|
504
|
+
|
505
|
+
EXAMPLES::
|
506
|
+
|
507
|
+
sage: T = OrderedTree([[],[]])
|
508
|
+
sage: T.to_dyck_word() # needs sage.combinat
|
509
|
+
[1, 0, 1, 0]
|
510
|
+
sage: T = OrderedTree([[],[[]]])
|
511
|
+
sage: T.to_dyck_word() # needs sage.combinat
|
512
|
+
[1, 0, 1, 1, 0, 0]
|
513
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
514
|
+
sage: T.to_dyck_word() # needs sage.combinat
|
515
|
+
[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0]
|
516
|
+
"""
|
517
|
+
word = []
|
518
|
+
for child in self:
|
519
|
+
word.append(1)
|
520
|
+
word.extend(child.to_dyck_word())
|
521
|
+
word.append(0)
|
522
|
+
from sage.combinat.dyck_word import DyckWord
|
523
|
+
return DyckWord(word)
|
524
|
+
|
525
|
+
@combinatorial_map(name="To graph")
|
526
|
+
def to_undirected_graph(self):
|
527
|
+
r"""
|
528
|
+
Return the undirected graph obtained from the tree nodes and edges.
|
529
|
+
|
530
|
+
The graph is endowed with an embedding, so that it will be displayed
|
531
|
+
correctly.
|
532
|
+
|
533
|
+
EXAMPLES::
|
534
|
+
|
535
|
+
sage: t = OrderedTree([])
|
536
|
+
sage: t.to_undirected_graph()
|
537
|
+
Graph on 1 vertex
|
538
|
+
sage: t = OrderedTree([[[]],[],[]])
|
539
|
+
sage: t.to_undirected_graph()
|
540
|
+
Graph on 5 vertices
|
541
|
+
|
542
|
+
If the tree is labelled, we use its labelling to label the graph. This
|
543
|
+
will fail if the labels are not all distinct.
|
544
|
+
Otherwise, we use the graph canonical labelling which means that
|
545
|
+
two different trees can have the same graph.
|
546
|
+
|
547
|
+
EXAMPLES::
|
548
|
+
|
549
|
+
sage: t = OrderedTree([[[]],[],[]])
|
550
|
+
sage: t.canonical_labelling().to_undirected_graph()
|
551
|
+
Graph on 5 vertices
|
552
|
+
|
553
|
+
TESTS::
|
554
|
+
|
555
|
+
sage: t.canonical_labelling().to_undirected_graph() == t.to_undirected_graph()
|
556
|
+
False
|
557
|
+
sage: OrderedTree([[],[]]).to_undirected_graph() == OrderedTree([[[]]]).to_undirected_graph()
|
558
|
+
True
|
559
|
+
sage: OrderedTree([[],[],[]]).to_undirected_graph() == OrderedTree([[[[]]]]).to_undirected_graph()
|
560
|
+
False
|
561
|
+
"""
|
562
|
+
from sage.graphs.graph import Graph
|
563
|
+
g = Graph()
|
564
|
+
if self in LabelledOrderedTrees():
|
565
|
+
relabel = False
|
566
|
+
else:
|
567
|
+
self = self.canonical_labelling()
|
568
|
+
relabel = True
|
569
|
+
roots = [self]
|
570
|
+
g.add_vertex(name=self.label())
|
571
|
+
emb = {self.label(): []}
|
572
|
+
while roots:
|
573
|
+
node = roots.pop()
|
574
|
+
children = reversed([child.label() for child in node])
|
575
|
+
emb[node.label()].extend(children)
|
576
|
+
for child in node:
|
577
|
+
g.add_vertex(name=child.label())
|
578
|
+
emb[child.label()] = [node.label()]
|
579
|
+
g.add_edge(child.label(), node.label())
|
580
|
+
roots.append(child)
|
581
|
+
g.set_embedding(emb)
|
582
|
+
if relabel:
|
583
|
+
g = g.canonical_label()
|
584
|
+
return g
|
585
|
+
|
586
|
+
@combinatorial_map(name="To poset")
|
587
|
+
def to_poset(self, root_to_leaf=False):
|
588
|
+
r"""
|
589
|
+
Return the poset obtained by interpreting the tree as a Hasse
|
590
|
+
diagram. The default orientation is from leaves to root but you can
|
591
|
+
pass ``root_to_leaf=True`` to obtain the inverse orientation.
|
592
|
+
|
593
|
+
INPUT:
|
594
|
+
|
595
|
+
- ``root_to_leaf`` -- boolean (default: ``False``); ``True`` if the
|
596
|
+
poset orientation should be from root to leaves
|
597
|
+
|
598
|
+
EXAMPLES::
|
599
|
+
|
600
|
+
sage: t = OrderedTree([])
|
601
|
+
sage: t.to_poset()
|
602
|
+
Finite poset containing 1 elements
|
603
|
+
sage: p = OrderedTree([[[]],[],[]]).to_poset()
|
604
|
+
sage: p.height(), p.width() # needs networkx
|
605
|
+
(3, 3)
|
606
|
+
|
607
|
+
If the tree is labelled, we use its labelling to label the poset.
|
608
|
+
Otherwise, we use the poset canonical labelling::
|
609
|
+
|
610
|
+
sage: t = OrderedTree([[[]],[],[]]).canonical_labelling().to_poset()
|
611
|
+
sage: t.height(), t.width() # needs networkx
|
612
|
+
(3, 3)
|
613
|
+
"""
|
614
|
+
if self in LabelledOrderedTrees():
|
615
|
+
relabel = False
|
616
|
+
else:
|
617
|
+
self = self.canonical_labelling()
|
618
|
+
relabel = True
|
619
|
+
relations = []
|
620
|
+
elements = [self.label()]
|
621
|
+
roots = [self]
|
622
|
+
while roots:
|
623
|
+
node = roots.pop()
|
624
|
+
for child in node:
|
625
|
+
elements.append(child.label())
|
626
|
+
relations.append((node.label(), child.label())
|
627
|
+
if root_to_leaf else (child.label(),
|
628
|
+
node.label()))
|
629
|
+
roots.append(child)
|
630
|
+
from sage.combinat.posets.posets import Poset
|
631
|
+
p = Poset([elements, relations])
|
632
|
+
if relabel:
|
633
|
+
p = p.canonical_label()
|
634
|
+
return p
|
635
|
+
|
636
|
+
@combinatorial_map(order=2, name="Left-right symmetry")
|
637
|
+
def left_right_symmetry(self):
|
638
|
+
r"""
|
639
|
+
Return the symmetric tree of ``self``.
|
640
|
+
|
641
|
+
The symmetric tree `s(T)` of an ordered tree `T` is
|
642
|
+
defined as follows:
|
643
|
+
If `T` is an ordered tree with children `C_1, C_2, \ldots, C_k`
|
644
|
+
(listed from left to right), then the symmetric tree `s(T)` of
|
645
|
+
`T` is the ordered tree with children
|
646
|
+
`s(C_k), s(C_{k-1}), \ldots, s(C_1)` (from left to right).
|
647
|
+
|
648
|
+
EXAMPLES::
|
649
|
+
|
650
|
+
sage: T = OrderedTree([[],[[]]])
|
651
|
+
sage: T.left_right_symmetry()
|
652
|
+
[[[]], []]
|
653
|
+
sage: T = OrderedTree([[], [[], []], [[], [[]]]])
|
654
|
+
sage: T.left_right_symmetry()
|
655
|
+
[[[[]], []], [[], []], []]
|
656
|
+
"""
|
657
|
+
children = [c.left_right_symmetry() for c in self]
|
658
|
+
children.reverse()
|
659
|
+
return OrderedTree(children)
|
660
|
+
|
661
|
+
def plot(self):
|
662
|
+
r"""
|
663
|
+
Plot the tree ``self``.
|
664
|
+
|
665
|
+
.. WARNING::
|
666
|
+
|
667
|
+
For a labelled tree, this will fail unless all labels are
|
668
|
+
distinct. For unlabelled trees, some arbitrary labels are chosen.
|
669
|
+
Use :meth:`_latex_`, ``view``,
|
670
|
+
:meth:`_ascii_art_` or ``pretty_print`` for more
|
671
|
+
faithful representations of the data of the tree.
|
672
|
+
|
673
|
+
EXAMPLES::
|
674
|
+
|
675
|
+
sage: p = OrderedTree([[[]],[],[]])
|
676
|
+
sage: ascii_art(p)
|
677
|
+
_o__
|
678
|
+
/ / /
|
679
|
+
o o o
|
680
|
+
|
|
681
|
+
o
|
682
|
+
sage: p.plot() # needs sage.plot
|
683
|
+
Graphics object consisting of 10 graphics primitives
|
684
|
+
|
685
|
+
.. PLOT::
|
686
|
+
|
687
|
+
P = OrderedTree([[[]],[],[]]).plot()
|
688
|
+
sphinx_plot(P)
|
689
|
+
|
690
|
+
Now a labelled example::
|
691
|
+
|
692
|
+
sage: g = OrderedTree([[],[[]],[]]).canonical_labelling()
|
693
|
+
sage: ascii_art(g)
|
694
|
+
_1__
|
695
|
+
/ / /
|
696
|
+
2 3 5
|
697
|
+
|
|
698
|
+
4
|
699
|
+
sage: g.plot() # needs sage.plot
|
700
|
+
Graphics object consisting of 10 graphics primitives
|
701
|
+
|
702
|
+
.. PLOT::
|
703
|
+
|
704
|
+
P = OrderedTree([[],[[]],[]]).canonical_labelling().plot()
|
705
|
+
sphinx_plot(P)
|
706
|
+
"""
|
707
|
+
try:
|
708
|
+
root = self.label()
|
709
|
+
g = self.to_undirected_graph()
|
710
|
+
except AttributeError:
|
711
|
+
root = 1
|
712
|
+
g = self.canonical_labelling().to_undirected_graph()
|
713
|
+
return g.plot(layout='tree', tree_root=root, tree_orientation='down')
|
714
|
+
|
715
|
+
def sort_key(self):
|
716
|
+
"""
|
717
|
+
Return a tuple of nonnegative integers encoding the ordered
|
718
|
+
tree ``self``.
|
719
|
+
|
720
|
+
The first entry of the tuple is the number of children of the
|
721
|
+
root. Then the rest of the tuple is the concatenation of the
|
722
|
+
tuples associated to these children (we view the children of
|
723
|
+
a tree as trees themselves) from left to right.
|
724
|
+
|
725
|
+
This tuple characterizes the tree uniquely, and can be used to
|
726
|
+
sort the ordered trees.
|
727
|
+
|
728
|
+
.. NOTE::
|
729
|
+
|
730
|
+
By default, this method does not encode any extra
|
731
|
+
structure that ``self`` might have -- e.g., if you were
|
732
|
+
to define a class ``EdgeColoredOrderedTree`` which
|
733
|
+
implements edge-colored trees and which inherits from
|
734
|
+
:class:`OrderedTree`, then the :meth:`sort_key` method
|
735
|
+
it would inherit would forget about the colors of the
|
736
|
+
edges (and thus would not characterize edge-colored
|
737
|
+
trees uniquely). If you want to preserve extra data,
|
738
|
+
you need to override this method or use a new method.
|
739
|
+
For instance, on the :class:`LabelledOrderedTree`
|
740
|
+
subclass, this method is overridden by a slightly
|
741
|
+
different method, which encodes not only the numbers
|
742
|
+
of children of the nodes of ``self``, but also their
|
743
|
+
labels.
|
744
|
+
Be careful with using overridden methods, however:
|
745
|
+
If you have (say) a class ``BalancedTree`` which
|
746
|
+
inherits from :class:`OrderedTree` and which encodes
|
747
|
+
balanced trees, and if you have another class
|
748
|
+
``BalancedLabelledOrderedTree`` which inherits both
|
749
|
+
from ``BalancedOrderedTree`` and from
|
750
|
+
:class:`LabelledOrderedTree`, then (depending on the MRO)
|
751
|
+
the default :meth:`sort_key` method on
|
752
|
+
``BalancedLabelledOrderedTree`` (unless manually
|
753
|
+
overridden) will be taken either from ``BalancedTree``
|
754
|
+
or from :class:`LabelledOrderedTree`, and in the former
|
755
|
+
case will ignore the labelling!
|
756
|
+
|
757
|
+
EXAMPLES::
|
758
|
+
|
759
|
+
sage: RT = OrderedTree
|
760
|
+
sage: RT([[],[[]]]).sort_key()
|
761
|
+
(2, 0, 1, 0)
|
762
|
+
sage: RT([[[]],[]]).sort_key()
|
763
|
+
(2, 1, 0, 0)
|
764
|
+
"""
|
765
|
+
l = len(self)
|
766
|
+
if l == 0:
|
767
|
+
return (0,)
|
768
|
+
resu = [l] + [u for t in self for u in t.sort_key()]
|
769
|
+
return tuple(resu)
|
770
|
+
|
771
|
+
@cached_method
|
772
|
+
def normalize(self, inplace=False):
|
773
|
+
r"""
|
774
|
+
Return the normalized tree of ``self``.
|
775
|
+
|
776
|
+
INPUT:
|
777
|
+
|
778
|
+
- ``inplace`` -- boolean (default: ``False``); if ``True``,
|
779
|
+
then ``self`` is modified and nothing returned. Otherwise
|
780
|
+
the normalized tree is returned.
|
781
|
+
|
782
|
+
The normalization of an ordered tree `t` is an ordered tree `s`
|
783
|
+
which has the property that `t` and `s` are isomorphic as
|
784
|
+
*unordered* rooted trees, and that if two ordered trees `t` and
|
785
|
+
`t'` are isomorphic as *unordered* rooted trees, then the
|
786
|
+
normalizations of `t` and `t'` are identical. In other words,
|
787
|
+
normalization is a map from the set of ordered trees to itself
|
788
|
+
which picks a representative from every equivalence class with
|
789
|
+
respect to the relation of "being isomorphic as unordered
|
790
|
+
trees", and maps every ordered tree to the representative
|
791
|
+
chosen from its class.
|
792
|
+
|
793
|
+
This map proceeds recursively by first normalizing every
|
794
|
+
subtree, and then sorting the subtrees according to the value
|
795
|
+
of the :meth:`sort_key` method.
|
796
|
+
|
797
|
+
Consider the quotient map `\pi` that sends a planar rooted tree to
|
798
|
+
the associated unordered rooted tree. Normalization is the
|
799
|
+
composite `s \circ \pi`, where `s` is a section of `\pi`.
|
800
|
+
|
801
|
+
EXAMPLES::
|
802
|
+
|
803
|
+
sage: OT = OrderedTree
|
804
|
+
sage: ta = OT([[],[[]]])
|
805
|
+
sage: tb = OT([[[]],[]])
|
806
|
+
sage: ta.normalize() == tb.normalize()
|
807
|
+
True
|
808
|
+
sage: ta == tb
|
809
|
+
False
|
810
|
+
|
811
|
+
An example with inplace normalization::
|
812
|
+
|
813
|
+
sage: OT = OrderedTree
|
814
|
+
sage: ta = OT([[],[[]]])
|
815
|
+
sage: tb = OT([[[]],[]])
|
816
|
+
sage: ta.normalize(inplace=True); ta
|
817
|
+
[[], [[]]]
|
818
|
+
sage: tb.normalize(inplace=True); tb
|
819
|
+
[[], [[]]]
|
820
|
+
"""
|
821
|
+
if not inplace:
|
822
|
+
with self.clone() as res:
|
823
|
+
resl = res._get_list()
|
824
|
+
for i in range(len(resl)):
|
825
|
+
resl[i] = resl[i].normalize()
|
826
|
+
resl.sort(key=lambda t: t.sort_key())
|
827
|
+
return res
|
828
|
+
else:
|
829
|
+
resl = self._get_list()
|
830
|
+
for i in range(len(resl)):
|
831
|
+
resl[i] = resl[i].normalize()
|
832
|
+
resl.sort(key=lambda t: t.sort_key())
|
833
|
+
|
834
|
+
|
835
|
+
# Abstract class to serve as a Factory no instance are created.
|
836
|
+
class OrderedTrees(UniqueRepresentation, Parent):
|
837
|
+
"""
|
838
|
+
Factory for ordered trees.
|
839
|
+
|
840
|
+
INPUT:
|
841
|
+
|
842
|
+
- ``size`` -- integer (optional)
|
843
|
+
|
844
|
+
OUTPUT:
|
845
|
+
|
846
|
+
- the set of all ordered trees (of the given ``size`` if specified)
|
847
|
+
|
848
|
+
EXAMPLES::
|
849
|
+
|
850
|
+
sage: OrderedTrees()
|
851
|
+
Ordered trees
|
852
|
+
|
853
|
+
sage: OrderedTrees(2)
|
854
|
+
Ordered trees of size 2
|
855
|
+
|
856
|
+
.. NOTE:: this is a factory class whose constructor returns instances of
|
857
|
+
subclasses.
|
858
|
+
|
859
|
+
.. NOTE:: the fact that OrderedTrees is a class instead of a simple callable
|
860
|
+
is an implementation detail. It could be changed in the future
|
861
|
+
and one should not rely on it.
|
862
|
+
"""
|
863
|
+
@staticmethod
|
864
|
+
def __classcall_private__(cls, n=None):
|
865
|
+
"""
|
866
|
+
TESTS::
|
867
|
+
|
868
|
+
sage: from sage.combinat.ordered_tree import OrderedTrees_all, OrderedTrees_size
|
869
|
+
sage: isinstance(OrderedTrees(2), OrderedTrees)
|
870
|
+
True
|
871
|
+
sage: isinstance(OrderedTrees(), OrderedTrees)
|
872
|
+
True
|
873
|
+
sage: OrderedTrees(2) is OrderedTrees_size(2)
|
874
|
+
True
|
875
|
+
sage: OrderedTrees(5).cardinality()
|
876
|
+
14
|
877
|
+
sage: OrderedTrees() is OrderedTrees_all()
|
878
|
+
True
|
879
|
+
"""
|
880
|
+
if n is None:
|
881
|
+
return OrderedTrees_all()
|
882
|
+
else:
|
883
|
+
if not (isinstance(n, (Integer, int)) and n >= 0):
|
884
|
+
raise ValueError("n must be a nonnegative integer")
|
885
|
+
return OrderedTrees_size(Integer(n))
|
886
|
+
|
887
|
+
@cached_method
|
888
|
+
def leaf(self):
|
889
|
+
"""
|
890
|
+
Return a leaf tree with ``self`` as parent.
|
891
|
+
|
892
|
+
EXAMPLES::
|
893
|
+
|
894
|
+
sage: OrderedTrees().leaf()
|
895
|
+
[]
|
896
|
+
|
897
|
+
TESTS::
|
898
|
+
|
899
|
+
sage: (OrderedTrees().leaf() is
|
900
|
+
....: sage.combinat.ordered_tree.OrderedTrees_all().leaf())
|
901
|
+
True
|
902
|
+
"""
|
903
|
+
return self([])
|
904
|
+
|
905
|
+
|
906
|
+
class OrderedTrees_all(DisjointUnionEnumeratedSets, OrderedTrees):
|
907
|
+
"""
|
908
|
+
The set of all ordered trees.
|
909
|
+
|
910
|
+
EXAMPLES::
|
911
|
+
|
912
|
+
sage: OT = OrderedTrees(); OT
|
913
|
+
Ordered trees
|
914
|
+
sage: OT.cardinality()
|
915
|
+
+Infinity
|
916
|
+
"""
|
917
|
+
|
918
|
+
def __init__(self):
|
919
|
+
"""
|
920
|
+
TESTS::
|
921
|
+
|
922
|
+
sage: from sage.combinat.ordered_tree import OrderedTrees_all
|
923
|
+
sage: B = OrderedTrees_all()
|
924
|
+
sage: B.cardinality()
|
925
|
+
+Infinity
|
926
|
+
|
927
|
+
sage: it = iter(B)
|
928
|
+
sage: (next(it), next(it), next(it), next(it), next(it))
|
929
|
+
([], [[]], [[], []], [[[]]], [[], [], []])
|
930
|
+
sage: next(it).parent()
|
931
|
+
Ordered trees
|
932
|
+
sage: B([])
|
933
|
+
[]
|
934
|
+
|
935
|
+
sage: B is OrderedTrees_all()
|
936
|
+
True
|
937
|
+
sage: TestSuite(B).run() # long time
|
938
|
+
"""
|
939
|
+
DisjointUnionEnumeratedSets.__init__(
|
940
|
+
self, Family(NonNegativeIntegers(), OrderedTrees_size),
|
941
|
+
facade=True, keepkey=False)
|
942
|
+
|
943
|
+
def _repr_(self):
|
944
|
+
"""
|
945
|
+
TESTS::
|
946
|
+
|
947
|
+
sage: OrderedTrees() # indirect doctest
|
948
|
+
Ordered trees
|
949
|
+
"""
|
950
|
+
return "Ordered trees"
|
951
|
+
|
952
|
+
def __contains__(self, x):
|
953
|
+
"""
|
954
|
+
TESTS::
|
955
|
+
|
956
|
+
sage: T = OrderedTrees()
|
957
|
+
sage: 1 in T
|
958
|
+
False
|
959
|
+
sage: T([]) in T
|
960
|
+
True
|
961
|
+
"""
|
962
|
+
return isinstance(x, self.element_class)
|
963
|
+
|
964
|
+
def unlabelled_trees(self):
|
965
|
+
"""
|
966
|
+
Return the set of unlabelled trees associated to ``self``.
|
967
|
+
|
968
|
+
EXAMPLES::
|
969
|
+
|
970
|
+
sage: OrderedTrees().unlabelled_trees()
|
971
|
+
Ordered trees
|
972
|
+
"""
|
973
|
+
return self
|
974
|
+
|
975
|
+
def labelled_trees(self):
|
976
|
+
"""
|
977
|
+
Return the set of labelled trees associated to ``self``.
|
978
|
+
|
979
|
+
EXAMPLES::
|
980
|
+
|
981
|
+
sage: OrderedTrees().labelled_trees()
|
982
|
+
Labelled ordered trees
|
983
|
+
"""
|
984
|
+
return LabelledOrderedTrees()
|
985
|
+
|
986
|
+
def _element_constructor_(self, *args, **keywords):
|
987
|
+
"""
|
988
|
+
EXAMPLES::
|
989
|
+
|
990
|
+
sage: T = OrderedTrees()
|
991
|
+
sage: T([]) # indirect doctest
|
992
|
+
[]
|
993
|
+
"""
|
994
|
+
return self.element_class(self, *args, **keywords)
|
995
|
+
|
996
|
+
Element = OrderedTree
|
997
|
+
|
998
|
+
|
999
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
1000
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
1001
|
+
from sage.combinat.composition import Compositions
|
1002
|
+
#################################################################
|
1003
|
+
# Enumerated set of binary trees of a given size
|
1004
|
+
#################################################################
|
1005
|
+
|
1006
|
+
|
1007
|
+
class OrderedTrees_size(OrderedTrees):
|
1008
|
+
"""
|
1009
|
+
The enumerated sets of binary trees of a given size.
|
1010
|
+
|
1011
|
+
EXAMPLES::
|
1012
|
+
|
1013
|
+
sage: S = OrderedTrees(3); S
|
1014
|
+
Ordered trees of size 3
|
1015
|
+
sage: S.cardinality()
|
1016
|
+
2
|
1017
|
+
sage: S.list()
|
1018
|
+
[[[], []], [[[]]]]
|
1019
|
+
"""
|
1020
|
+
|
1021
|
+
def __init__(self, size):
|
1022
|
+
"""
|
1023
|
+
TESTS::
|
1024
|
+
|
1025
|
+
sage: from sage.combinat.ordered_tree import OrderedTrees_size
|
1026
|
+
sage: TestSuite(OrderedTrees_size(0)).run()
|
1027
|
+
sage: for i in range(6): TestSuite(OrderedTrees_size(i)).run()
|
1028
|
+
"""
|
1029
|
+
super().__init__(category=FiniteEnumeratedSets())
|
1030
|
+
self._size = size
|
1031
|
+
|
1032
|
+
def _repr_(self):
|
1033
|
+
"""
|
1034
|
+
TESTS::
|
1035
|
+
|
1036
|
+
sage: OrderedTrees(3) # indirect doctest
|
1037
|
+
Ordered trees of size 3
|
1038
|
+
"""
|
1039
|
+
return "Ordered trees of size {}".format(self._size)
|
1040
|
+
|
1041
|
+
def __contains__(self, x):
|
1042
|
+
"""
|
1043
|
+
TESTS::
|
1044
|
+
|
1045
|
+
sage: T = OrderedTrees(3)
|
1046
|
+
sage: 1 in T
|
1047
|
+
False
|
1048
|
+
sage: T([[],[]]) in T
|
1049
|
+
True
|
1050
|
+
"""
|
1051
|
+
return isinstance(x, self.element_class) and x.node_number() == self._size
|
1052
|
+
|
1053
|
+
def _an_element_(self):
|
1054
|
+
"""
|
1055
|
+
TESTS::
|
1056
|
+
|
1057
|
+
sage: OrderedTrees(3).an_element() # indirect doctest
|
1058
|
+
[[], []]
|
1059
|
+
"""
|
1060
|
+
if self._size == 0:
|
1061
|
+
raise EmptySetError
|
1062
|
+
return self.first()
|
1063
|
+
|
1064
|
+
def cardinality(self):
|
1065
|
+
"""
|
1066
|
+
The cardinality of ``self``.
|
1067
|
+
|
1068
|
+
This is a Catalan number.
|
1069
|
+
|
1070
|
+
TESTS::
|
1071
|
+
|
1072
|
+
sage: OrderedTrees(0).cardinality()
|
1073
|
+
0
|
1074
|
+
sage: OrderedTrees(1).cardinality()
|
1075
|
+
1
|
1076
|
+
sage: OrderedTrees(6).cardinality()
|
1077
|
+
42
|
1078
|
+
"""
|
1079
|
+
if self._size == 0:
|
1080
|
+
return Integer(0)
|
1081
|
+
else:
|
1082
|
+
from .combinat import catalan_number
|
1083
|
+
return catalan_number(self._size - 1)
|
1084
|
+
|
1085
|
+
def random_element(self):
|
1086
|
+
"""
|
1087
|
+
Return a random ``OrderedTree`` with uniform probability.
|
1088
|
+
|
1089
|
+
This method generates a random ``DyckWord`` and then uses a
|
1090
|
+
bijection between Dyck words and ordered trees.
|
1091
|
+
|
1092
|
+
EXAMPLES::
|
1093
|
+
|
1094
|
+
sage: OrderedTrees(5).random_element() # random # needs sage.combinat
|
1095
|
+
[[[], []], []]
|
1096
|
+
sage: OrderedTrees(0).random_element()
|
1097
|
+
Traceback (most recent call last):
|
1098
|
+
...
|
1099
|
+
EmptySetError: there are no ordered trees of size 0
|
1100
|
+
sage: OrderedTrees(1).random_element() # needs sage.combinat
|
1101
|
+
[]
|
1102
|
+
|
1103
|
+
TESTS::
|
1104
|
+
|
1105
|
+
sage: all(OrderedTrees(10).random_element() in OrderedTrees(10) # needs sage.combinat
|
1106
|
+
....: for i in range(20))
|
1107
|
+
True
|
1108
|
+
"""
|
1109
|
+
if self._size == 0:
|
1110
|
+
raise EmptySetError("there are no ordered trees of size 0")
|
1111
|
+
return CompleteDyckWords_size(self._size - 1).random_element().to_ordered_tree()
|
1112
|
+
|
1113
|
+
def __iter__(self):
|
1114
|
+
"""
|
1115
|
+
A basic generator.
|
1116
|
+
|
1117
|
+
.. TODO:: could be optimized.
|
1118
|
+
|
1119
|
+
TESTS::
|
1120
|
+
|
1121
|
+
sage: OrderedTrees(0).list()
|
1122
|
+
[]
|
1123
|
+
sage: OrderedTrees(1).list()
|
1124
|
+
[[]]
|
1125
|
+
sage: OrderedTrees(2).list()
|
1126
|
+
[[[]]]
|
1127
|
+
sage: OrderedTrees(3).list()
|
1128
|
+
[[[], []], [[[]]]]
|
1129
|
+
sage: OrderedTrees(4).list()
|
1130
|
+
[[[], [], []], [[], [[]]], [[[]], []], [[[], []]], [[[[]]]]]
|
1131
|
+
"""
|
1132
|
+
if self._size == 0:
|
1133
|
+
return
|
1134
|
+
for c in Compositions(self._size - 1):
|
1135
|
+
for lst in itertools.product(*[self.__class__(i) for i in c]):
|
1136
|
+
yield self._element_constructor_(lst)
|
1137
|
+
|
1138
|
+
@lazy_attribute
|
1139
|
+
def _parent_for(self):
|
1140
|
+
"""
|
1141
|
+
Return the parent of the element generated by ``self``.
|
1142
|
+
|
1143
|
+
TESTS::
|
1144
|
+
|
1145
|
+
sage: OrderedTrees(3)._parent_for
|
1146
|
+
Ordered trees
|
1147
|
+
"""
|
1148
|
+
return OrderedTrees_all()
|
1149
|
+
|
1150
|
+
@lazy_attribute
|
1151
|
+
def element_class(self):
|
1152
|
+
"""
|
1153
|
+
The class of the element of ``self``.
|
1154
|
+
|
1155
|
+
EXAMPLES::
|
1156
|
+
|
1157
|
+
sage: from sage.combinat.ordered_tree import OrderedTrees_size, OrderedTrees_all
|
1158
|
+
sage: S = OrderedTrees_size(3)
|
1159
|
+
sage: S.element_class is OrderedTrees().element_class
|
1160
|
+
True
|
1161
|
+
sage: S.first().__class__ == OrderedTrees_all().first().__class__
|
1162
|
+
True
|
1163
|
+
"""
|
1164
|
+
return self._parent_for.element_class
|
1165
|
+
|
1166
|
+
def _element_constructor_(self, *args, **keywords):
|
1167
|
+
"""
|
1168
|
+
EXAMPLES::
|
1169
|
+
|
1170
|
+
sage: S = OrderedTrees(0)
|
1171
|
+
sage: S([]) # indirect doctest
|
1172
|
+
Traceback (most recent call last):
|
1173
|
+
...
|
1174
|
+
ValueError: wrong number of nodes
|
1175
|
+
|
1176
|
+
sage: S = OrderedTrees(1) # indirect doctest
|
1177
|
+
sage: S([])
|
1178
|
+
[]
|
1179
|
+
"""
|
1180
|
+
res = self.element_class(self._parent_for, *args, **keywords)
|
1181
|
+
if res.node_number() != self._size:
|
1182
|
+
raise ValueError("wrong number of nodes")
|
1183
|
+
return res
|
1184
|
+
|
1185
|
+
|
1186
|
+
class LabelledOrderedTree(AbstractLabelledClonableTree, OrderedTree):
|
1187
|
+
"""
|
1188
|
+
Labelled ordered trees.
|
1189
|
+
|
1190
|
+
A labelled ordered tree is an ordered tree with a label attached at each
|
1191
|
+
node.
|
1192
|
+
|
1193
|
+
INPUT:
|
1194
|
+
|
1195
|
+
- ``children`` -- list or tuple or more generally any iterable
|
1196
|
+
of trees or object convertible to trees
|
1197
|
+
- ``label`` -- any Sage object (default: ``None``)
|
1198
|
+
|
1199
|
+
EXAMPLES::
|
1200
|
+
|
1201
|
+
sage: x = LabelledOrderedTree([], label = 3); x
|
1202
|
+
3[]
|
1203
|
+
sage: LabelledOrderedTree([x, x, x], label = 2)
|
1204
|
+
2[3[], 3[], 3[]]
|
1205
|
+
sage: LabelledOrderedTree((x, x, x), label = 2)
|
1206
|
+
2[3[], 3[], 3[]]
|
1207
|
+
sage: LabelledOrderedTree([[],[[], []]], label = 3)
|
1208
|
+
3[None[], None[None[], None[]]]
|
1209
|
+
"""
|
1210
|
+
@staticmethod
|
1211
|
+
def __classcall_private__(cls, *args, **opts):
|
1212
|
+
"""
|
1213
|
+
Ensure that trees created by the sets and directly are the same and
|
1214
|
+
that they are instances of :class:`LabelledOrderedTree`
|
1215
|
+
|
1216
|
+
TESTS::
|
1217
|
+
|
1218
|
+
sage: issubclass(LabelledOrderedTrees().element_class, LabelledOrderedTree)
|
1219
|
+
True
|
1220
|
+
sage: t0 = LabelledOrderedTree([[],[[], []]], label = 3)
|
1221
|
+
sage: t0.parent()
|
1222
|
+
Labelled ordered trees
|
1223
|
+
sage: type(t0)
|
1224
|
+
<class 'sage.combinat.ordered_tree.LabelledOrderedTrees_with_category.element_class'>
|
1225
|
+
"""
|
1226
|
+
return cls._auto_parent.element_class(cls._auto_parent, *args, **opts)
|
1227
|
+
|
1228
|
+
@lazy_class_attribute
|
1229
|
+
def _auto_parent(cls):
|
1230
|
+
"""
|
1231
|
+
The automatic parent of the elements of this class.
|
1232
|
+
|
1233
|
+
When calling the constructor of an element of this class, one needs a
|
1234
|
+
parent. This class attribute specifies which parent is used.
|
1235
|
+
|
1236
|
+
EXAMPLES::
|
1237
|
+
|
1238
|
+
sage: LabelledOrderedTree._auto_parent
|
1239
|
+
Labelled ordered trees
|
1240
|
+
sage: LabelledOrderedTree([], label = 3).parent()
|
1241
|
+
Labelled ordered trees
|
1242
|
+
"""
|
1243
|
+
return LabelledOrderedTrees()
|
1244
|
+
|
1245
|
+
_UnLabelled = OrderedTree
|
1246
|
+
|
1247
|
+
__hash__ = ClonableArray.__hash__
|
1248
|
+
|
1249
|
+
@combinatorial_map(order=2, name="Left-right symmetry")
|
1250
|
+
def left_right_symmetry(self):
|
1251
|
+
r"""
|
1252
|
+
Return the symmetric tree of ``self``.
|
1253
|
+
|
1254
|
+
The symmetric tree `s(T)` of a labelled ordered tree `T` is
|
1255
|
+
defined as follows:
|
1256
|
+
If `T` is a labelled ordered tree with children
|
1257
|
+
`C_1, C_2, \ldots, C_k` (listed from left to right), then the
|
1258
|
+
symmetric tree `s(T)` of `T` is a labelled ordered tree with
|
1259
|
+
children `s(C_k), s(C_{k-1}), \ldots, s(C_1)` (from left to
|
1260
|
+
right), and with the same root label as `T`.
|
1261
|
+
|
1262
|
+
.. NOTE::
|
1263
|
+
|
1264
|
+
If you have a subclass of :meth:`LabelledOrderedTree`
|
1265
|
+
which also inherits from another subclass of
|
1266
|
+
:meth:`OrderedTree` which does not come with a labelling,
|
1267
|
+
then (depending on the method resolution order) it might
|
1268
|
+
happen that this method gets overridden by an
|
1269
|
+
implementation from that other subclass, and thus forgets
|
1270
|
+
about the labels. In this case you need to manually
|
1271
|
+
override this method on your subclass.
|
1272
|
+
|
1273
|
+
EXAMPLES::
|
1274
|
+
|
1275
|
+
sage: L2 = LabelledOrderedTree([], label=2)
|
1276
|
+
sage: L3 = LabelledOrderedTree([], label=3)
|
1277
|
+
sage: T23 = LabelledOrderedTree([L2, L3], label=4)
|
1278
|
+
sage: T23.left_right_symmetry()
|
1279
|
+
4[3[], 2[]]
|
1280
|
+
sage: T223 = LabelledOrderedTree([L2, T23], label=17)
|
1281
|
+
sage: T223.left_right_symmetry()
|
1282
|
+
17[4[3[], 2[]], 2[]]
|
1283
|
+
sage: T223.left_right_symmetry().left_right_symmetry() == T223
|
1284
|
+
True
|
1285
|
+
"""
|
1286
|
+
children = [c.left_right_symmetry() for c in self]
|
1287
|
+
children.reverse()
|
1288
|
+
return LabelledOrderedTree(children, label=self.label())
|
1289
|
+
|
1290
|
+
def sort_key(self):
|
1291
|
+
"""
|
1292
|
+
Return a tuple of nonnegative integers encoding the labelled
|
1293
|
+
tree ``self``.
|
1294
|
+
|
1295
|
+
The first entry of the tuple is a pair consisting of the
|
1296
|
+
number of children of the root and the label of the root. Then
|
1297
|
+
the rest of the tuple is the concatenation of the tuples
|
1298
|
+
associated to these children (we view the children of
|
1299
|
+
a tree as trees themselves) from left to right.
|
1300
|
+
|
1301
|
+
This tuple characterizes the labelled tree uniquely, and can
|
1302
|
+
be used to sort the labelled ordered trees provided that the
|
1303
|
+
labels belong to a type which is totally ordered.
|
1304
|
+
|
1305
|
+
.. WARNING::
|
1306
|
+
|
1307
|
+
This method overrides :meth:`OrderedTree.sort_key`
|
1308
|
+
and returns a result different from what the latter
|
1309
|
+
would return, as it wants to encode the whole labelled
|
1310
|
+
tree including its labelling rather than just the
|
1311
|
+
unlabelled tree. Therefore, be careful with using this
|
1312
|
+
method on subclasses of :class:`LabelledOrderedTree`;
|
1313
|
+
under some circumstances they could inherit it from
|
1314
|
+
another superclass instead of from :class:`OrderedTree`,
|
1315
|
+
which would cause the method to forget the labelling.
|
1316
|
+
See the docstring of :meth:`OrderedTree.sort_key`.
|
1317
|
+
|
1318
|
+
EXAMPLES::
|
1319
|
+
|
1320
|
+
sage: L2 = LabelledOrderedTree([], label=2)
|
1321
|
+
sage: L3 = LabelledOrderedTree([], label=3)
|
1322
|
+
sage: T23 = LabelledOrderedTree([L2, L3], label=4)
|
1323
|
+
sage: T23.sort_key()
|
1324
|
+
((2, 4), (0, 2), (0, 3))
|
1325
|
+
sage: T32 = LabelledOrderedTree([L3, L2], label=5)
|
1326
|
+
sage: T32.sort_key()
|
1327
|
+
((2, 5), (0, 3), (0, 2))
|
1328
|
+
sage: T23322 = LabelledOrderedTree([T23, T32, L2], label=14)
|
1329
|
+
sage: T23322.sort_key()
|
1330
|
+
((3, 14), (2, 4), (0, 2), (0, 3), (2, 5), (0, 3), (0, 2), (0, 2))
|
1331
|
+
"""
|
1332
|
+
l = len(self)
|
1333
|
+
if l == 0:
|
1334
|
+
return ((0, self.label()),)
|
1335
|
+
resu = [(l, self.label())] + [u for t in self for u in t.sort_key()]
|
1336
|
+
return tuple(resu)
|
1337
|
+
|
1338
|
+
|
1339
|
+
class LabelledOrderedTrees(UniqueRepresentation, Parent):
|
1340
|
+
"""
|
1341
|
+
This is a parent stub to serve as a factory class for trees with various
|
1342
|
+
label constraints.
|
1343
|
+
|
1344
|
+
EXAMPLES::
|
1345
|
+
|
1346
|
+
sage: LOT = LabelledOrderedTrees(); LOT
|
1347
|
+
Labelled ordered trees
|
1348
|
+
sage: x = LOT([], label = 3); x
|
1349
|
+
3[]
|
1350
|
+
sage: x.parent() is LOT
|
1351
|
+
True
|
1352
|
+
sage: y = LOT([x, x, x], label = 2); y
|
1353
|
+
2[3[], 3[], 3[]]
|
1354
|
+
sage: y.parent() is LOT
|
1355
|
+
True
|
1356
|
+
"""
|
1357
|
+
|
1358
|
+
def __init__(self, category=None):
|
1359
|
+
"""
|
1360
|
+
TESTS::
|
1361
|
+
|
1362
|
+
sage: TestSuite(LabelledOrderedTrees()).run()
|
1363
|
+
"""
|
1364
|
+
if category is None:
|
1365
|
+
category = Sets()
|
1366
|
+
Parent.__init__(self, category=category)
|
1367
|
+
|
1368
|
+
def _repr_(self):
|
1369
|
+
"""
|
1370
|
+
TESTS::
|
1371
|
+
|
1372
|
+
sage: LabelledOrderedTrees() # indirect doctest
|
1373
|
+
Labelled ordered trees
|
1374
|
+
"""
|
1375
|
+
return "Labelled ordered trees"
|
1376
|
+
|
1377
|
+
def cardinality(self):
|
1378
|
+
"""
|
1379
|
+
Return the cardinality of ``self``.
|
1380
|
+
|
1381
|
+
EXAMPLES::
|
1382
|
+
|
1383
|
+
sage: LabelledOrderedTrees().cardinality()
|
1384
|
+
+Infinity
|
1385
|
+
"""
|
1386
|
+
return Infinity
|
1387
|
+
|
1388
|
+
def _an_element_(self):
|
1389
|
+
"""
|
1390
|
+
Return a labelled ordered tree.
|
1391
|
+
|
1392
|
+
EXAMPLES::
|
1393
|
+
|
1394
|
+
sage: LabelledOrderedTrees().an_element() # indirect doctest
|
1395
|
+
toto[3[], 42[3[], 3[]], 5[None[]]]
|
1396
|
+
"""
|
1397
|
+
LT = self._element_constructor_
|
1398
|
+
t = LT([], label=3)
|
1399
|
+
t1 = LT([t, t], label=42)
|
1400
|
+
t2 = LT([[]], label=5)
|
1401
|
+
return LT([t, t1, t2], label='toto')
|
1402
|
+
|
1403
|
+
def _element_constructor_(self, *args, **keywords):
|
1404
|
+
"""
|
1405
|
+
EXAMPLES::
|
1406
|
+
|
1407
|
+
sage: T = LabelledOrderedTrees()
|
1408
|
+
sage: T([], label=2) # indirect doctest
|
1409
|
+
2[]
|
1410
|
+
"""
|
1411
|
+
return self.element_class(self, *args, **keywords)
|
1412
|
+
|
1413
|
+
def unlabelled_trees(self):
|
1414
|
+
"""
|
1415
|
+
Return the set of unlabelled trees associated to ``self``.
|
1416
|
+
|
1417
|
+
This is the set of ordered trees, since ``self`` is the set of
|
1418
|
+
labelled ordered trees.
|
1419
|
+
|
1420
|
+
EXAMPLES::
|
1421
|
+
|
1422
|
+
sage: LabelledOrderedTrees().unlabelled_trees()
|
1423
|
+
Ordered trees
|
1424
|
+
"""
|
1425
|
+
return OrderedTrees_all()
|
1426
|
+
|
1427
|
+
def labelled_trees(self):
|
1428
|
+
"""
|
1429
|
+
Return the set of labelled trees associated to ``self``.
|
1430
|
+
|
1431
|
+
This is precisely ``self``, because ``self`` already is the set
|
1432
|
+
of labelled ordered trees.
|
1433
|
+
|
1434
|
+
EXAMPLES::
|
1435
|
+
|
1436
|
+
sage: LabelledOrderedTrees().labelled_trees()
|
1437
|
+
Labelled ordered trees
|
1438
|
+
sage: LOT = LabelledOrderedTrees()
|
1439
|
+
sage: x = LOT([], label = 3)
|
1440
|
+
sage: y = LOT([x, x, x], label = 2)
|
1441
|
+
sage: y.canonical_labelling()
|
1442
|
+
1[2[], 3[], 4[]]
|
1443
|
+
"""
|
1444
|
+
return self
|
1445
|
+
|
1446
|
+
Element = LabelledOrderedTree
|